尝试在blockingcollection上取性能

本文关键字:性能 blockingcollection | 更新日期: 2023-09-27 18:01:17

我有一个程序有时运行得很慢。

我尝试了Teleriks Justtrace来找出可能导致应用程序挂起的原因。

一个非UI线程(因此我相信它不是真正的挂起的原因)做assync。获取对象(Enqueues工作项)并请求它做一些工作。

排队:

public void EnqueueObject(WorkUnit workunit)
        {
            try
            {
                workUnits.Add(workunit);
            }
            catch (Exception ex)
            {
                /handle exception
            }
        }

出列:

public WorkUnit Dequeue()
        {
            try
            {
                WorkUnit aWorkUnit  = null;
                workUnits.TryTake(out aWorkUnit, 1000);
                return aWorkUnit ;
            }
            catch (InvalidOperationException ex)
            {
                // 
            }
                    return null;
        }

TryTake用于检查当前工作的中止(而不是BlockingCollection Complete方法,它在调用时只抛出一些错误-我不想在程序流程中使用错误)

调用去队列:

 while(!isStopped)
 {
   ProcessWorkItem(Dequeue());
 }

到目前为止,它看起来很简单。

问题是,Teleriks JustTrace显示,"workUnits"这一行。TryTake(out aWorkUnit, 1000);"占用程序总执行时间的30%。

这是怎么回事?

更多的细节显示,在TryTake System.Threading.Monitor.Wait中占用了所有的时间——我认为Wait会将一个线程发送到睡眠状态,所以它在等待期间不会消耗任何东西。这个想法的错误在哪里?

尝试在blockingcollection上取性能

您可以尝试使用不带timeout参数的workUnits.TryTake(out aWorkUnit)。然后,您应该将while循环修改为如下所示:

 while(!isStopped)
 {
    WorkUnit wu = Dequeue(); 
    if(wu != null) 
       ProcessWorkItem(wu);
    else
       Thread.Sleep(40);
 }

同样,如果你在一个UI线程上运行这段代码,它将使你的UI无响应。例如,您应该使用BackgroundWorker进行操作。以下是MSDN文档中BackgroundWorker类的描述:

BackgroundWorker类允许你在一个单独的专用线程上运行一个操作。下载和数据库事务等耗时的操作可能会导致用户界面(UI)在运行时看起来好像停止了响应。当你想要一个响应的UI,并且你面临着与这些操作相关的长时间延迟时,BackgroundWorker类提供了一个方便的解决方案。