尝试使用阻塞收集功能

时间:2013-02-27 10:59:02

标签: c# performance

我有一个程序,有时运行速度非常慢。

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

非UI线程(因此我认为它不是挂起的原因)确实是同步。获取对象(排队工作项)并将其除去以进行一些工作。

入队:

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会发送一个线程进入休眠状态,因此在等待期间它不会消耗掉一些东西。想法中的错误在哪里?

1 个答案:

答案 0 :(得分:0)

您可以尝试使用workUnits.TryTake(out aWorkUnit)而不使用timeout参数。然后,您应该修改while循环以使其类似于:

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

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

  

BackgroundWorker类允许您在单独的专用线程上运行操作。下载和数据库事务等耗时的操作可能会导致用户界面(UI)在运行时停止响应。当您需要响应式UI并且您遇到与此类操作相关的长时间延迟时,BackgroundWorker类提供了一种方便的解决方案。