";“任务包”;C#中的概念、排队、暂停、取消逻辑任务

";“任务包”;C#中的概念、排队、暂停、取消逻辑任务,c#,task-parallel-library,.net-4.5,C#,Task Parallel Library,.net 4.5,我正在开发的应用程序是这样组成的: 生产者任务扫描文件系统中的文本文件,并将它们的引用放入一个包中。 许多使用者任务同时从包中获取文件引用并读取文件(并对其内容做一些简短的工作) 我必须能够暂停并恢复整个过程 我尝试过使用TPL,在文件放入包中时为每个文件引用创建一个任务(在本例中,包只是一个概念,生产者在找到文件时直接创建消费者任务),但这种方式我无法控制我创建的任务,我无法(或我不知道如何)暂停它们。我可以编写一些代码来挂起当前正在执行任务的线程,但这会破坏处理逻辑任务而不是手动创建线程的意

我正在开发的应用程序是这样组成的: 生产者任务扫描文件系统中的文本文件,并将它们的引用放入一个包中。 许多使用者任务同时从包中获取文件引用并读取文件(并对其内容做一些简短的工作)

我必须能够暂停并恢复整个过程

我尝试过使用TPL,在文件放入包中时为每个文件引用创建一个任务(在本例中,包只是一个概念,生产者在找到文件时直接创建消费者任务),但这种方式我无法控制我创建的任务,我无法(或我不知道如何)暂停它们。我可以编写一些代码来挂起当前正在执行任务的线程,但这会破坏处理逻辑任务而不是手动创建线程的意义,不是吗?我希望类似“已分配给物理线程的任务可以完成,但等待的逻辑任务不应启动,直到恢复命令”

我怎样才能做到这一点?我可以用第三方物流吗?还是应该用别的什么

编辑: 你的回答都是正确的,但我的主要疑问仍未得到解答。我们谈论的是任务,如果我使用TPL,我的生产者和消费者将是任务(对吗?)而不是线程(好吧,在执行任务时,任务将映射到线程上)。我发现的每个同步机制(如“ManualResetEventSlim”注释中提出的同步机制)都在线程级别工作

例如,“ManualResetEventSlim”的Wait()方法的描述是“在设置当前ManualResetEventSlim之前阻止当前线程。”


我对任务的了解纯粹是学术性的,我不知道“现实世界”中的事情是如何运作的,但我认为我需要一种方法在任务级别协调(等待/信号/…)任务,否则事情可能会变得奇怪。。。喜欢两个任务可能映射到同一个线程上,但其中一个应该向另一个等待的线程发出信号,然后死锁。我有点困惑。这就是为什么我问我的应用程序是否可以使用TPL而不是老式的简单线程。

是的,你可以这样做。首先,您有一个主线程,即您的应用程序。这里有两个worker,由线程表示。第一个工人是生产者,第二个工人是消费者

当应用程序启动时,您启动工人。它们都对并发集合bag进行操作。生产者搜索文件并将引用放在包中,消费者从包中获取引用并根据引用启动任务

当您想发出暂停信号时,只需暂停制作人。如果您这样做,如果袋子里什么都没有,消费者也会停止工作。如果这不是一个理想的行为,您可以简单地定义生产者的暂停也会清除行李-首先备份您的行李,然后再清除它。这样,所有正在运行的任务都将完成其作业,使用者不会启动新任务,但仍可运行并等待结果

编辑:

根据您的编辑。我不知道如何以你想要的方式实现它,但尽管尝试使用新技术很好,但不要让你的头脑变得模糊。使用
ThreadPool
也是一件好事。启动应用程序需要更多的时间,但一旦应用程序运行,消耗将更快,因为您已经准备好了工作人员


这不是一个坏主意,您可以指定最大工作人数。如果您为包中的每个项目创建一个任务,它将消耗更多内存,因为您仍将分配和释放内存。使用
线程池时不会发生这种情况

请确保您可以使用TPL进行此操作。也可以使用和LINQ来简化分组和线程工作

如果您对每个文件都有一个简短的作业,最好不要用取消来干扰处理程序函数。您可以暂停工作人员的排队

我想象这样的情况:

  • 目录扫描线程将找到的文件放入可观察的集合中
  • 使用者线程订阅集合更改,获取/删除文件并将其分配给工作线程

是的,您必须自己创建暂停机制。使用消费者反复等待的
ManualResetEventSlim
,生产者设置/重置暂停/恢复。正常的
任务始终在单个线程上执行。因此,在
线程
s上工作的任何同步原语也可以与
任务
s一起工作。@svick如果我启动100个任务,执行包含Wait()的相同代码,该怎么办?根据这个问题的公认答案,将创建100个等待线程,好吗?@flagg19我认为答案是错误的(至少对于.Net 4.5而言)。但如果不调用
ThreadPool.SetMaxThreads()
,则最终将创建100个线程。这并不理想,所以如果你不想这样,你就得做点什么。在集合中使用委托而不是
Task
s,然后使用数量有限的
Task
s来处理委托(可以使用
Parallel.ForEach()
)。另一种选择是使用。@svick谢谢,我想我会选择“在集合中使用代理而不是任务,然后使用有限数量的任务来处理它们”。这不是我想要的答案,但感谢你提出的清理/备份包的想法。是的,从我的观点来看,这是一个更好的解决方案。如果您发送暂停应用程序的通知,请清理您的包,让您的消费者线程使用线程暂停自己。如果包中没有任何内容,请睡眠。但这取决于你的要求。有了并发性,您就可以尝试优化应用程序了。