代码之家  ›  专栏  ›  技术社区  ›  JohnW

640个企业库缓存线程-如何?

  •  2
  • JohnW  · 技术社区  · 16 年前

    我们有一个正在进行性能测试的应用程序。今天,我决定把w3wp&把它装进windbg看看盖子下面发生了什么。想象一下我跑步时的惊讶吧!线程,看到有640个后台线程,几乎所有的线程都是这样说的:

    OS Thread Id: 0x1c38 (651)
    Child-SP         RetAddr          Call Site
    0000000023a9d290 000007ff002320e2 Microsoft.Practices.EnterpriseLibrary.Caching.ProducerConsumerQueue.WaitUntilInterrupted()
    0000000023a9d2d0 000007ff00231f7e Microsoft.Practices.EnterpriseLibrary.Caching.ProducerConsumerQueue.Dequeue()
    0000000023a9d330 000007fef727c978 Microsoft.Practices.EnterpriseLibrary.Caching.BackgroundScheduler.QueueReader()
    0000000023a9d380 000007fef9001552 System.Threading.ExecutionContext.runTryCode(System.Object)
    0000000023a9dc30 000007fef72f95fd System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
    0000000023a9dc80 000007fef9001552 System.Threading.ThreadHelper.ThreadStart()

    如果非要我猜的话,我想我们的应用程序每次运行都会产生一个线程-我们有2个应用程序服务器,20个并发用户,并且运行了大约30次测试…就在附近。

    编辑:谢谢大家的回复。有人要求显示关于调用堆栈的更多细节-这里是的输出!来自sosex.dll的mk。

    
         ESP              RetAddr
    00:U 0000000023a9cb38 00000000775f72ca ntdll!ZwWaitForMultipleObjects+0xa
    01:U 0000000023a9cb40 00000000773cbc03 kernel32!WaitForMultipleObjectsEx+0x10b
    02:U 0000000023a9cc50 000007fef8f5f595 mscorwks!WaitForMultipleObjectsEx_SO_TOLERANT+0xc1
    03:U 0000000023a9ccf0 000007fef8f59f49 mscorwks!Thread::DoAppropriateAptStateWait+0x41
    04:U 0000000023a9cd50 000007fef8e55b99 mscorwks!Thread::DoAppropriateWaitWorker+0x191
    05:U 0000000023a9ce50 000007fef8e2efe8 mscorwks!Thread::DoAppropriateWait+0x5c
    06:U 0000000023a9cec0 000007fef8f0dc7a mscorwks!CLREvent::WaitEx+0xbe
    07:U 0000000023a9cf70 000007fef8fba72e mscorwks!Thread::Block+0x1e
    08:U 0000000023a9cfa0 000007fef8e1996d mscorwks!SyncBlock::Wait+0x195
    09:U 0000000023a9d0c0 000007fef9463d3f mscorwks!ObjectNative::WaitTimeout+0x12f
    0a:M 0000000023a9d290 000007ff002321b3 *** ERROR: Module load completed but symbols could not be loaded for Microsoft.Practices.EnterpriseLibrary.Caching.DLL
    Microsoft.Practices.EnterpriseLibrary.Caching.ProducerConsumerQueue.WaitUntilInterrupted()(+0x0 IL)(+0x11 Native)
    0b:M 0000000023a9d2d0 000007ff002320e2 Microsoft.Practices.EnterpriseLibrary.Caching.ProducerConsumerQueue.Dequeue()(+0xf IL)(+0x18 Native)
    0c:M 0000000023a9d330 000007ff00231f7e Microsoft.Practices.EnterpriseLibrary.Caching.BackgroundScheduler.QueueReader()(+0x9 IL)(+0x12 Native)
    0d:M 0000000023a9d380 000007fef727c978 System.Threading.ExecutionContext.runTryCode(System.Object)(+0x18 IL)(+0x106 Native)
    0e:U 0000000023a9d440 000007fef9001552 mscorwks!CallDescrWorker+0x82
    0f:U 0000000023a9d490 000007fef8e9e5e3 mscorwks!CallDescrWorkerWithHandler+0xd3
    10:U 0000000023a9d530 000007fef8eac83f mscorwks!MethodDesc::CallDescr+0x24f
    11:U 0000000023a9d790 000007fef8f0cbd2 mscorwks!ExecuteCodeWithGuaranteedCleanupHelper+0x12a
    12:U 0000000023a9da20 000007fef945e572 mscorwks!ReflectionInvocation::ExecuteCodeWithGuaranteedCleanup+0x172
    13:M 0000000023a9dc30 000007fef7261722 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)(+0x60 IL)(+0x51 Native)
    14:M 0000000023a9dc80 000007fef72f95fd System.Threading.ThreadHelper.ThreadStart()(+0x8 IL)(+0x2a Native)
    15:U 0000000023a9dcd0 000007fef9001552 mscorwks!CallDescrWorker+0x82
    16:U 0000000023a9dd20 000007fef8e9e5e3 mscorwks!CallDescrWorkerWithHandler+0xd3
    17:U 0000000023a9ddc0 000007fef8eac83f mscorwks!MethodDesc::CallDescr+0x24f
    18:U 0000000023a9e010 000007fef8f9ae8d mscorwks!ThreadNative::KickOffThread_Worker+0x191
    19:U 0000000023a9e330 000007fef8f59374 mscorwks!TypeHandle::GetParent+0x5c
    1a:U 0000000023a9e380 000007fef8e52045 mscorwks!SVR::gc_heap::make_heap_segment+0x155
    1b:U 0000000023a9e450 000007fef8f66139 mscorwks!ZapStubPrecode::GetType+0x39
    1c:U 0000000023a9e490 000007fef8e1c985 mscorwks!ILCodeStream::GetToken+0x25
    1d:U 0000000023a9e4c0 000007fef8f594e1 mscorwks!Thread::DoADCallBack+0x145
    1e:U 0000000023a9e630 000007fef8f59399 mscorwks!TypeHandle::GetParent+0x81
    1f:U 0000000023a9e680 000007fef8e52045 mscorwks!SVR::gc_heap::make_heap_segment+0x155
    20:U 0000000023a9e750 000007fef8f66139 mscorwks!ZapStubPrecode::GetType+0x39
    21:U 0000000023a9e790 000007fef8e20e15 mscorwks!ThreadNative::KickOffThread+0x401
    22:U 0000000023a9e7f0 000007fef8e20ae7 mscorwks!ThreadNative::KickOffThread+0xd3
    23:U 0000000023a9e8d0 000007fef8f814fc mscorwks!Thread::intermediateThreadProc+0x78
    24:U 0000000023a9f7a0 00000000773cbe3d kernel32!BaseThreadInitThunk+0xd
    25:U 0000000023a9f7d0 00000000775d6a51 ntdll!RtlUserThreadStart+0x1d
    
    4 回复  |  直到 16 年前
        1
  •  3
  •   Chris Tavares    16 年前

    是的,缓存块对于旧版本的Entlib中的清理线程有一些问题,特别是当事情进入的速度比清理设置允许的快时。

    这是在entlib5中完全重写的,所以现在缓存块中的线程不会超过两个,不管负载如何,而且通常只有一个。

        2
  •  2
  •   dthorpe    16 年前

    如果应用程序设置了一个主线程,该线程在线程句柄上等待线程何时退出,而后台线程陷入循环或等待状态,并且从不退出线程进程,那么进程及其所有线程将永远不会退出。

    检查线程代码,确保每个threadproc都有一个退出threadproc的清晰路径。在后台线程中编写一个无限循环是一种不好的形式,因为它假设在进程关闭时线程将被强制终止。

    如果后台线程代码在循环中旋转,等待事件句柄发出信号,请确保您有某种方法来发出该事件的信号,以便线程可以正常有序地退出。否则,您需要编写后台线程来等待多个事件,并在任何一个事件发出信号时取消阻止。这些事件中的一个可以是后台线程主要感兴趣的活动,另一个可以是关闭事件。

    从您发布的堆栈转储中的对象名称来看,线程似乎正在等待某个对象出现在ProducerConsumerQueue中。研究应该如何关闭队列对象(可能是在生产者端),以及关闭队列是否会自动释放等待该队列的所有使用者。

    我的猜测是,要么队列没有被正确关闭,要么关闭它并不意味着释放等待它的消费者。如果是后一种情况,您可能需要通过队列发送一条terminate消息,以唤醒等待该队列的所有消费者,并告诉他们脱离等待循环并退出。

        3
  •  1
  •   Naveen    16 年前

    你有个大问题。每一个线程占用1MB的堆栈,在上下文中切换每一个线程是要付出很大的代价的。尤其是托管代码的情况更糟,因为每次GC必须运行时,它都要遍历线程堆栈以查找根,当这些线程被分页到磁盘时,从磁盘读取的成本很高,这就增加了性能问题。

    创建线程是不好的,除非你知道你在做什么?杰弗里·里希特(Jeffery Richter)对此进行了详细的描述。

    为了解决上述问题,我将查看这些线程被阻塞在什么上,并在线程创建上设置断点(例如windbg中的sxe ct)

    稍后重新构建避免创建线程,而是使用线程池。

        4
  •  1
  •   plodoc    16 年前

    在MicrosoftEnterpriseLibrary4.1中,BackgroundScheduler类在每次实例化对象时都会创建一个新线程。会的 fixed http://entlib.codeplex.com/wikipage?title=EntLib5%20Beta2