C#相当于Java ExecutorService.newSingleThreadExecutor(),或:如何序列化对资源的多线程访问
我的代码中有几种情况,不同的线程可以创建工作项,由于各种原因,这些工作项不应该并行完成。我想确保工作以先进先出的方式完成,不管它来自哪个线程。在Java中,我将工作项放在一个单线程的C#相当于Java ExecutorService.newSingleThreadExecutor(),或:如何序列化对资源的多线程访问,c#,.net,multithreading,concurrency,C#,.net,Multithreading,Concurrency,我的代码中有几种情况,不同的线程可以创建工作项,由于各种原因,这些工作项不应该并行完成。我想确保工作以先进先出的方式完成,不管它来自哪个线程。在Java中,我将工作项放在一个单线程的ExecutorService;C#中是否有等价物?我用队列和一堆lock(){}块拼凑了一些东西,但是如果能够使用现成的东西并进行测试,那就太好了 更新:是否有人拥有System.Threading.Tasks的经验?它有解决这类问题的办法吗?我正在写一个Monotouch应用程序,所以谁知道我是否能找到一个可以开
ExecutorService
;C#中是否有等价物?我用队列
和一堆lock(){}
块拼凑了一些东西,但是如果能够使用现成的东西并进行测试,那就太好了
更新:是否有人拥有System.Threading.Tasks的经验?它有解决这类问题的办法吗?我正在写一个Monotouch应用程序,所以谁知道我是否能找到一个可以开始工作的后端口版本,但这至少是未来需要考虑的事情
更新#2对于不熟悉我所说的Java库的C#开发人员来说,基本上我想要的是一种让各个线程传递工作项的东西,这样所有这些工作项都将在一个线程(不是任何调用线程)上运行
更新,2018年6月:如果我现在正在设计一个类似的系统,我可能会使用。不过,我要留下公认的一个,因为如果你在Rx中思考,你可能甚至不会问这个问题,我认为
ConcurrentQueue
更容易进入预Rx程序。不是本地的AFAIK,但看看这个:
我相信这可以通过使用。然而,我这样做只是为了回发到UI线程,它已经有了由.NET提供的同步上下文(如果被告知要安装的话)——不过我不知道如何准备从“普通线程”使用它
我为“custom synchronizationcontext provider”找到了一些链接(我没有时间查看这些链接,不完全了解工作/上下文,也没有任何其他信息):
愉快的编码。正如我在评论中所写,您自己发现
lock
语句可以完成这项工作
如果您有兴趣获得一个“容器”,它可以简化管理工作项队列的工作,请查看ThreadPool
类
我认为,在一个设计良好的体系结构中,有了这两个元素(
ThreadPool
类和lock
语句),您可以轻松成功地序列化对资源的访问。更新:解决关于浪费资源的评论(如果您没有使用Rx),您可以使用BlockingCollection
(如果使用默认构造函数,它会包装一个ConcurrentQueue
),只需调用.getconsumineGenumerable()
。如果工作是长时间运行的,则会有一个重载占用CancellationToken
。请参见下面的示例
您可以使用(如果monotouch支持.NET4?)它是线程安全的,我认为它的实现实际上是无锁的。如果您有一个长时间运行的任务(比如在windows服务中),那么这个方法非常有效 通常,您的问题听起来像是有多个生产者和一个消费者
var work = new BlockingCollection<Item>();
var producer1 = Task.Factory.StartNew(() => {
work.TryAdd(item); // or whatever your threads are doing
});
var producer2 = Task.Factory.StartNew(() => {
work.TryAdd(item); // etc
});
var consumer = Task.Factory.StartNew(() => {
foreach (var item in work.GetConsumingEnumerable()) {
// do the work
}
});
Task.WaitAll(producer1, producer2, consumer);
var work=new BlockingCollection();
var producer1=Task.Factory.StartNew(()=>{
work.TryAdd(item);//或线程正在执行的任何操作
});
var producer2=Task.Factory.StartNew(()=>{
work.TryAdd(项);//等
});
var consumer=Task.Factory.StartNew(()=>{
foreach(work.GetConsumingEnumerable()中的变量项){
//做这项工作
}
});
Task.WaitAll(生产者1、生产者2、消费者);
如果您有一个有限的工作项池,则应该使用。显示所有新的并发收集类型。现在有一个更现代的解决方案-类。如果工作应该以FIFO方式完成,为什么要创建“各种”线程?为什么不在单个线程上工作?@标记各种线程的存在还有其他原因——一些工作是由UI活动触发的,一些是由对网络请求的响应触发的,一些是由计时器触发的。对于这个问题:“如何序列化对资源的多线程访问?”您自己回答:在资源上使用lock()语句(或包含它们的物体)。我问题中的相关短语是“拼凑在一起”,而你答案中的相关短语是“在精心设计的建筑中”。事实上,虽然我不会残忍地否决它,“工具是存在的,去弄清楚如何建造它”这根本不是一个答案。你可以投票否决所有你想要的。我没有时间做一个完整的例子让你复制粘贴并完成你的工作。你写了关于队列的文章,我想你用它来管理线程,我建议你看看ThreadPool类来简化你的工作。怎么了?!是的,如果我在做那个项目的话现在我再次使用Rx架构。虽然此解决方案可能与Java解决方案具有相同的结果,
使用者
线程将继续运行。TryDequeue
仅提供并发安全性,但如果队列中没有元素,它将不会继续等待。如果队列中没有元素,则有一个阅读正在运行的while循环。Java版本绝对不会像这样浪费资源。相比于此,wait
-notify
解决方案更可取。您可以使用BlockingCollection.CompleteAdding()方法,该方法将阻止foreach使用者线程进一步运行。