c#阻塞收集和线程

Posted

技术标签:

【中文标题】c#阻塞收集和线程【英文标题】:c# Blocking Collection and Threading 【发布时间】:2017-03-13 08:54:57 【问题描述】:

我是使用 Blocking Collection 和线程的新手,我想确保我遵循最佳实践。我正在使用非线程安全的第三方 API。我将同时向 API 发出多个请求,因此我需要将这些请求添加到队列中并一个接一个地处理它们。为此,我有一个阻塞集合:

    BlockingCollection<myEventArgs> myTasks = new BlockingCollection<myEventArgs>();

    private void myEventHandler(object sender, myEventArgs e)
    
        myTasks.Add(e);
    

    private void doWork()
    

        while (myTasks.IsCompleted == false)
        

        //Do some work here with the third party API. 
        var eArgs = myTasks.Take();

        //Sometimes I have a background (thread safe) task to perform.
        //This is submitted to the thread pool.
        Task.Run(() => doSomeBackgroundWork());

        
    

有时我会执行一个线程安全的后台任务。例如,API 调用是异步的,我需要轮询第三方系统以检查任务是否完成。我不希望这会阻止 BlockingCollection 处理下一个任务,所以我将它提交给线程池。一旦线程池任务完成,它将触发一个事件,该事件将一个新任务添加到 BlockingCollection。

此解决方案是否合适?是否有任何问题?我是否正确假设处理 BlockingCollection 中项目的 doWork 方法将始终在同一个线程中运行?而当我从线程池触发事件时,只有事件会在线程池上运行,而不是后续的doWork方法?

【问题讨论】:

我认为 DoWork() 需要一个循环,在它内部或周围。 是的,对不起,有一个循环,我只是解释了我的代码!为了清楚起见,我现在将其添加。 旁注,标准 C# 实践要求方法和类型使用 PascalCasing。 【参考方案1】:

这个解决方案合适吗

基本上,是的。这是一种生产者/消费者的情况,而这正是 BlockingCollection 的用途。

这有什么问题吗?

您必须非常确定 doSomeBackgroundWork() 对于您的 doWork() 代码是线程安全的。

根据可以推送的 myEventArgs 数量,为您的阻塞集合设置一个上限可能是个好主意。

【讨论】:

太好了,非常感谢。 doSomeBackgroundWork() 方法本质上是一个查询第三方作业管理器的 SQL 选择语句。它不会更新或改变任何东西,所以它应该是安全的。【参考方案2】:

我知道这是一个旧线程,但为了读者,我想指出,这样做与只产生没有阻塞集合的线程相同,因此删除了 BlockingCollection 的全部意义.

在这种情况下更合适的是管理线程数量,并且只产生特定数量的线程,同时消耗 BlockingCollection,这样可以确保不会同时产生太多线程

【讨论】:

是的,就像这个例子使用了四个线程:***.com/questions/22688679/…

以上是关于c#阻塞收集和线程的主要内容,如果未能解决你的问题,请参考以下文章

C#中垃圾收集的根是啥[重复]

C# 和 Java 中的垃圾收集

无阻塞 编程模型

有效地将图像文件保存到磁盘 c#

蚂蚁4轮面经(Java研发):悲观锁+G1收集器+幻读+连接池+分布式架构

JVM垃圾收集器和收集器的选择策略