I think that it would be great if Kernel.Register(....) takes care of this
automatically.
On Thu, Sep 17, 2009 at 8:43 PM, Ayende Rahien <[email protected]> wrote:
> No, it doesn't.
> It is easier with code.
> Test code is interesting, it shows a pathological case of adding only
> invalid components.
> And the problem only show up when we have a large number of invalid
> components.
>
> var kernel = new DefaultKernel();
> for (int i = 0; i < 500; i++)
> {
> kernel.AddComponent("key" + i, typeof(string), typeof(string));
> }
>
> Before optimization, this runs in 9.2 seconds
>
> After optimization, this runs in 0.5 seconds.
>
> Raising the number of components to 5,000 leads to about: 44.5 seconds (no
> idea how much before optimization, don't have the patience.
>
> Using this approach, however:
>
> var kernel = new DefaultKernel();
> using(kernel.OptimizeDependencyResolution())
> {
> for (int i = 0; i < 300; i++)
> {
> kernel.AddComponent("key" + i, typeof(string), typeof(string));
> }
> }
>
> Resolve everything in 1.9 seconds.
> The OptimizeDependencyResolution defer dependency resolution to the Dispose
> part, and allow us to both gain significant optimization in registering
> component while at the same time work nicely with all the usual tools and
> facilities.
>
> I also optimized GetHandlers(Type) and GetAssignableHandlers(Type)
>
> I think that this is good enough for now :-)
>
>
> On Fri, Sep 18, 2009 at 1:44 AM, Tyler Burd <[email protected]> wrote:
>
>> I fully accept that. Does this mean that the startable facility will
>> not be usable with this feature?
>>
>>
>>
>> *From:* [email protected] [mailto:
>> [email protected]] *On Behalf Of *Ayende Rahien
>> *Sent:* Thursday, September 17, 2009 3:53 PM
>>
>> *To:* [email protected]
>> *Subject:* Re: long startup time
>>
>>
>>
>> Hm, that is a bit complex, though.
>> In particular, it effect the way the startable facility behaves.
>> I think that I will make this an opt in feature.
>>
>> On Thu, Sep 17, 2009 at 10:55 PM, Ayende Rahien <[email protected]>
>> wrote:
>>
>> Tyler,
>> No, it isn't.
>> Basically, I think we need to restructure the way we do this so we will
>> defer that as late as possible (to the first resolve call, I think.).
>>
>>
>>
>> On Thu, Sep 17, 2009 at 8:09 PM, Tyler Burd <[email protected]> wrote:
>>
>> Attached is the profiling screenshot for a VERY simple console app (code
>> below). It took so long to profile that I didn't have the patience to wait
>> until all 1000 services were registered, but this clearly shows where the
>> problem lies.
>>
>> Total calls to AddComponent: 409
>> Total calls to AbstractHandler.DependencySatisfied: 83,773
>>
>>
>> If I try to profile my original app, it times out and causes a profiler
>> error even when left overnight to finish starting up. When I stopped the
>> profiler after 30 minutes of running I saw over 600,000 calls to
>> DependencySatisfied.
>>
>> Am I wrong in thinking that 1000 services is not THAT many in a well
>> designed app? I have a large financial app that has many complicated
>> processes, so I split out every process into isolated services. I also use
>> a service to encapsulate ever query with a dedicated service interface. The
>> number of services registered adds up fast, but it sure seems like the
>> right, maintainable, and testable way to do things.
>>
>>
>> Profiled code:
>>
>> var container = new WindsorContainer();
>> var kernel = container.Kernel;
>>
>> for (int i = 0; i < 1000; i++)
>> {
>> kernel.AddComponent("key" + i, typeof(string), typeof(string));
>> }
>>
>> Console.ReadLine();
>>
>>
>>
>>
>> -----Original Message-----
>> From: [email protected] [mailto:
>> [email protected]] On Behalf Of Mauricio Scheffer
>> Sent: Wednesday, September 16, 2009 8:28 PM
>> To: Castle Project Users
>> Subject: Re: long startup time
>>
>>
>> It's definitely the HandlerRegistered event, or more likely
>> AbstractEventHandler.DependencySatisfied()... here's a little test:
>>
>> import System
>> import System.Diagnostics
>> import Castle.Windsor from Castle.Windsor
>> import Castle.MicroKernel from Castle.MicroKernel
>> import Castle.MicroKernel.Handlers from Castle.MicroKernel
>> import Castle.MicroKernel.SubSystems.Naming from Castle.MicroKernel
>> import Castle.MicroKernel.ModelBuilder from Castle.MicroKernel
>>
>> def KernelAddComponent(k as IKernel):
>> for i in range(1000):
>> w = Stopwatch()
>> w.Start()
>> k.AddComponent("key${i}", typeof(string), typeof(string))
>> w.Stop()
>> print "${i} took ${w.ElapsedMilliseconds}"
>>
>> class CustomKernel(DefaultKernel):
>> override def RaiseHandlerRegistered(h as IHandler):
>> pass
>>
>> KernelAddComponent(DefaultKernel())
>>
>> Change the DefaultKernel() to CustomKernel() and the perf hit goes
>> away.
>>
>>
>> On Sep 16, 2:00 pm, Tuna Toksoz <[email protected]> wrote:
>> > N! times? How?
>> >
>> > Tuna Toksöz
>> > Eternal sunshine of the open source mind.
>> >
>> >
>> http://devlicio.us/blogs/tuna_toksozhttp://tunatoksoz.comhttp://twitter.com/tehlike<http://devlicio.us/blogs/tuna_toksozhttp:/tunatoksoz.comhttp:/twitter.com/tehlike>
>> >
>> >
>> >
>> > On Wed, Sep 16, 2009 at 12:59 PM, Ayende Rahien <[email protected]>
>> wrote:
>> > > IIRC, the culprit is the ComponentRegistered event, that is being
>> raised N!
>> > > times
>> > > We had to do that when we use the AddComponent model, but with
>> Register, we
>> > > can probably optimize this.
>> >
>> > > On Wed, Sep 16, 2009 at 7:54 PM, Tyler Burd <[email protected]> wrote:
>> >
>> > >> I'm not sure how feasible that idea could be. SO much of an
>> application
>> > >> depends on having everything registered and ready to go before any
>> actual
>> > >> services are invoked. For instance, my project uses Rhino Service
>> Bus,
>> > >> which depends heavily on the GetAssignableHandlers and similar
>> methods on
>> > >> the kernel. If a critical message came in and we weren't finished
>> > >> registering services (AKA Message Consumers), that message could be
>> lost
>> > >> forever since GetAssignableHandlers would not return all of the
>> expected
>> > >> handlers.
>> >
>> > >> I'd much rather have some form of lazy initialization of handlers and
>> > >> dependencies to amortize whatever this startup cost is, but I'm not
>> sure
>> > >> right now how that might look.
>> >
>> > >> -----Original Message-----
>> > >> From: [email protected] [mailto:
>> > >> [email protected]] On Behalf Of James Curran
>> > >> Sent: Wednesday, September 16, 2009 10:31 AM
>> > >> To: [email protected]
>> > >> Subject: Re: long startup time
>> >
>> > >> This leads to interesting question. Since, one presumes you won't
>> > >> need all 1000 service immediately, could building the container be
>> > >> spun off as a background task? This of course would lead to some
>> > >> interesting race conditions, but if most of those services are for
>> > >> corner cases (ie, say 90% of your functionality could be handled by
>> > >> 10% of the services), then it just become a case of filling it in th
>> > >> eproper order, and releasing semaphores as you go.
>> >
>> > >> On Wed, Sep 16, 2009 at 12:05 PM, Tyler Burd <[email protected]> wrote:
>> > >> > I have another similar project that has around 300 services, and
>> the
>> > >> average
>> > >> > AddComponent time there is 20ms, so that would make sense. I'll
>> try to
>> > >> get
>> > >> > profile results today (have to buy dotTrace first).
>> >
>> > >> > From: [email protected]
>> > >> > [mailto:[email protected]] On Behalf Of Ayende
>> > >> Rahien
>> > >> > Sent: Wednesday, September 16, 2009 3:00 AM
>> > >> > To: [email protected]
>> > >> > Subject: Re: long startup time
>> >
>> > >> > IIRC,
>> >
>> > >> > We saw something like that previously, I think that there is an
>> O(N)
>> > >> > operation in Windsor somewhere.
>> >
>> > >> > On Wed, Sep 16, 2009 at 7:19 AM, Tyler Burd <[email protected]>
>> wrote:
>> >
>> > >> > Hi all,
>> >
>> > >> > I've got a large application that takes about 1 minute to start up.
>> I
>> > >> > investigated today what could be the cause of this very long delay,
>> and
>> > >> > narrowed it down to the WindsorContainer.AddComponent method. I
>> have
>> > >> about
>> > >> > 1000 service classes, each with an interface (the service type).
>> The
>> > >> > average time to call WindsorContainer.AddComponent is 52ms on my
>> system.
>> > >> > 52ms * 1000 is 52 seconds, which is the vast majority of the app's
>> > >> startup
>> > >> > time.
>> >
>> > >> > My system is a Quad Core, 2.66GHz Core2 running Windows XP. The
>> same
>> > >> > approximate startup time can be verified on multiple machines,
>> servers,
>> > >> and
>> > >> > OS's.
>> >
>> > >> > Is this normal? Do I have to just bite the bullet on a long
>> startup
>> > >> time,
>> > >> > or is there something I can do to help this?
>> >
>> > >> > Here is the block of code in a small executable I used to calculate
>> the
>> > >> > times. I can provide a profile report if necessary. I normally
>> use
>> > >> > AllTypes along with the fluent registration, but I wanted to get as
>> > >> > low-level as possible. This code outputs:
>> >
>> > >> "Called AddComponent 957 times. Average AddComponent time:
>> 52.0267175572519ms"
>> >
>> > >> > var container = new WindsorContainer();
>> >
>> > >> > //calculates the time for each AddComponent call
>> >
>> > >> > var watch = new Stopwatch();
>> >
>> > >> > var totalAddComponentCalls = 0;
>> >
>> > >> > //keeps track of the average ms to call AddComponent
>> >
>> > >> > var allAddComponentTimes = new List<long>(1000);
>> >
>> > >> > foreach (var classType in
>> > >> >
>> typeof(TheBigApplicationThingyWithAllTheServices).Assembly.GetTypes())
>> >
>> > >> > {
>> >
>> > >> > if (classType.IsInterface)
>> >
>> > >> > continue;
>> >
>> > >> > if (classType.Namespace == null)
>> >
>> > >> > continue;
>> >
>> > >> > if (!classType.Namespace.Contains("Services"))
>> >
>> > >> > continue;
>> >
>> > >> > var interfaces = classType.GetInterfaces();
>> >
>> > >> > if (interfaces.Length == 0)
>> >
>> > >> > continue;
>> >
>> > >> > var firstInterface = interfaces[0];
>> >
>> > >> > var serviceName =
>> totalAddComponentCalls.ToString();
>> > >> > //simple way to get unique name
>> >
>> > >> > watch.Start();
>> >
>> > >> > container.AddComponent(serviceName, firstInterface,
>> > >> > classType);
>> >
>> > >> > watch.Stop();
>> >
>> > >> >
>> allAddComponentTimes.Add(watch.ElapsedMilliseconds);
>> >
>> > >> > watch.Reset();
>> >
>> > >> > ++totalAddComponentCalls;
>> >
>> > >> > }
>> >
>> > >> > var avgAddCompTime = (from ms in allAddComponentTimes select
>> > >> ms).Average();
>> >
>> > >> > Console.Out.WriteLine(string.Format("Called AddComponent {0} times.
>> > >> Average
>> > >> > AddComponent time: {1}ms", totalAddComponentCalls,
>> avgAddCompTime));
>> >
>> > >> --
>> > >> Truth,
>> > >> James
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>
> >
>
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Castle Project Users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/castle-project-users?hl=en
-~----------~----~----~----~------~----~------~--~---