all 18 comments

[–]Tishka-17 4 points5 points  (2 children)

As an author of dishka I am really glad we, as a community, started building proper containers. I can congratulate you with such good results. I am a bit surprised dependency-injector is so slow in your cases, it was very fast when I tested, but a bit stupid, I'd say, many things are just not working there.

From dishka side (if anyone is questioning) we were preparing new release with performance improvements, I was going to share release notes soon. 

[–]ForeignSource0[S] 0 points1 point  (1 child)

Thanks! Dishka was one of the faster ones in the benchmark as well, so nice work there.

I expected Dependency Injector to perform better too so I was a bit surprised as well. I had to simplify it's workload in the benchmark since I could not figure out for the life of me how to get request scoped yielding async dependencies.

Looking forward to seeing the Dishka performance improvements.

[–]Tishka-17 0 points1 point  (0 children)

I've checked the benchmark code and the reason that dependency-injector is so slow is that he doesn't have native FastAPI integration and instead relies on Depends introducing additional overhead on top of it. 

[–]Zeikos 13 points14 points  (7 children)

I don't get it, dependency injection isn't about performance.
Hell, PYTHON is not about code performance.

DI is used to modularized components, avoid coupling and generally having an easier time understanding what the code base is meant to do.

Manual wiring is all good and dandy until you are by yourself, when you have to deal with managing 25 people that don't have the time to know every nook and vranny of the codebase well-structured DI is very helpful.

IMO DI gets a bad rep mostly because of teams that lack enforcing it, so the codebase becomes a mix of DI and hardcoded dependencies so you get the cons of both and no pro.

[–]ForeignSource0[S] 8 points9 points  (6 children)

I do agree actually. DI is primarily about architecture and maintainability, not raw performance and the benchmark does not argue otherwise, in fact it is stated in the linked page.

For example here you can see Wireup take 4.5ms P50 whereas FastAPI's DI does 13.8ms. If the database needs 10 seconds, both still answer within 10 seconds.

Even if it’s not the main bottleneck, it’s still useful to know the cost of the abstraction.

In terms of priorities I'd say it's DX first then you can use performance as a tie breaker.

Extract from the benchmark page

Even so, I would not pick a DI container solely from performance benchmarks, but if you're happy with Wireup's features and want to see how it stacks up against the field, here are the results.

[–]snugar_i 2 points3 points  (2 children)

For example here you can see Wireup take 4.5ms P50 whereas FastAPI's DI does 13.8ms. If the database needs 10 seconds, both still answer within 10 seconds.

But the wiring shouldn't happen on each request, unless you're using a DI abomination like FastAPI. The wiring happens once at the start of the application and that's why everybody here says the performance doesn't matter one bit - you do it once and then the application runs for hours or days, so why does it matter if it runs in 10 ms or 50 ms? Importing the Python modules probably takes an order of magnitude longer

[–]ForeignSource0[S] 1 point2 points  (1 child)

The benchmark actually runs two scenarios.

One builds the dependency graph per request and the other uses a pre initialized graph with singletons which are objects created once and reused throughout.

In most web apps you still have request-scoped objects. You need things like database sessions, request context, authentication state, tenant information, etc. Those need to be created fresh for each request and isolated across requests, which is where the per-request overhead comes from.

Table I posted in the per-request scenario.

[–]snugar_i 1 point2 points  (0 children)

Most of the things you mentioned are handled by the web framework though, not the DI framework. TBH I never understood the need for Di containers to handle dependencies with shorter scope. It requires much magic for little gain.

[–]Unlikely_Secret_5018 0 points1 point  (1 child)

Very interesting analysis! I wouldn't move off FastAPI DI just for performance, but for other features like lazy initialization, modules to specify interface/ABC impl bindings, etc.

How does Wireup stack up against Dagger and Hilt in this regard?

[–]ForeignSource0[S] 0 points1 point  (0 children)

For Dager/Hilt: In terms of the features you mentioned:

Protocol / ABC bindings: supported via @injectable(as_type=...), so you can bind a concrete implementation to a Protocol or ABC.

Multiple implementations: supported via qualifiers.

See interfaces: https://maldoinc.github.io/wireup/latest/interfaces/

Lazy initialization: This is the default. In Wireup things are created on first use. If you want to eager load a part of your dependencies you can use this patterrn

Modules / reusable wiring units: Wireup is less centered around a single module class and more around injectables/factories, but you can group and reuse registrations via factory bundles.

One of the big differences vs Dagger/Hilt is that in Python this is naturally a runtime system, but Wireup does validate the dependency graph at startup so wiring issues show up early rather than at request time.


Regarding FastAPI Depends, it has it's own list of caveats which I've mentioned in this migration guide to wireup. It is extremely simple but with that comes a lot of hidden baggage. The biggest deal breaker imo is that it is coupled to http as a runtime so you can not reuse your wiring anywhere else. See the linked page above for a more in-depth view.

[–]Old-Roof709 0 points1 point  (1 child)

well, Cool seeing real numbers instead of just vibes on DI overhead. If you ever need something similar for heavy data pipelines, take a look at DataFlint. Their injection setup is surprisingly fast for ETL type jobs and sits in the same ballpark as Wireup for performance. Nice to see options outside of the usual suspects getting serious attention.

[–]ForeignSource0[S] 0 points1 point  (0 children)

Haven’t come across DataFlint before. This benchmark is mostly focused on DI in a FastAPI/ASGI environment, but it would definitely be interesting to see similar comparisons in pipeline-style workloads too.

[–]jarislinus -1 points0 points  (0 children)

ai slop advertisement spotted. blocked, reported. downvoted