我已经阅读了有关TPL的文档和许多教程,但没有一篇涵盖我想要实现的模型。
某些算法总是有固定的迭代次数。
我需要不断运行线程(尽可能多):
而(真)
另外我需要能够设置闹钟(例如5秒)的机制。五秒钟后,所有工作必须暂停一段时间,然后重新开始。
我应该使用Task.Continue与相同的任务吗?但我没有处理上一个任务启动的结果,而是更新MAIN线程中的数据结构,然后决定新任务迭代的输入...
我如何决定应该为最佳效率创建多少任务?
不,我正在使用BackgroundWorkers,因为他们有很好的RunEventCompleted事件 - 在我的主线程中,我可以更新我的MAIN结构,检查时间限制,然后最终在完成的BackgroundWorker上再次调用StartAsync。它很好而且清晰,但可能非常有用。 我需要在多处理器,多核服务器上实现高效率。
一个问题是计算总是在线,永远不会停止。还有一些网络,可以远程询问MAIN结构的当前状态。
第二个问题是关键的时间控制(我必须有精确的计时器 - 当它停止时,没有线程可以重新启动)。然后在结束后进行特殊的高优先级任务,恢复所有工作。
第三个问题是操作没有上限。
这三个约束,从我观察到的,并没有很好地进行TPL - 我不能使用像Parallel.For这样的东西,因为集合是由任务本身的实时结果修改的...... 我不知道如何结合:
有人可以给我提供线索吗? 我知道怎么做坏事,无所事事。我描述了一些小的要求,这使我无法做到这一点。我有点困惑。
答案 0 :(得分:3)
您需要使用消息+演员+调度程序imo。然后你需要使用一种能够满足它的语言。查看从Azure Service Bus异步接收的this code,在共享队列中排队并通过actor管理运行时状态。
内联:
我应该使用Task.Continue与相同的任务吗?
不,ContinueWith会根据每个延续传递中的异常处理来杀死你的程序;在TPL中没有好办法将失败的状态编组到呼叫方/主线程中。
但我没有处理上一个任务启动的结果,但是 而是更新数据结构 主线程然后决定新任务的输入是什么 迭代...
除非你愿意花很多时间来解决这个问题,否则你需要超越线程。
我如何决定应该为TPL决定创建多少任务 最佳效率?
这是由运行异步工作流的框架处理的。
不,我使用的是BackgroundWorkers,因为他们很好 RunEventCompleted事件 - 在我的主线程中,我可以 更新我的MAIN结构,检查时间限制,然后最终 在已完成的BackgroundWorker上再次调用StartAsync。它是 很好,很清楚,但可能非常有用。我需要做到 在多处理器,多核服务器上高效。
一个问题是计算总是在线,永远不会停止。那里 也是一些网络,它可以远程询问当前 主要结构状态。第二个问题是关键时间控制(I 必须有精确的计时器 - 当它停止时,没有线程可以 重新启动)。
如果以异步方式运行所有内容,则可以将消息传递给暂停它的actor。你安排的演员负责用他们的schedulled消息调用所有的订阅者;查看链接代码中的paused
状态。如果您有未完成的请求,您可以向他们传递取消令牌并处理“硬”取消/套接字中止。
然后在它结束后进入特殊的高优先级任务 工作重新开始。从我观察到的这两个约束来看,没有 顺利进行TPL - 我不能使用Parallel.For因为 该集合由任务本身的实时结果修改......
您可能需要一种称为管道和过滤器的模式。你将你的输入输入一系列工人(演员);每个工人都从其他工人的产出中消费。信令是使用控制通道完成的(在我的情况下是演员的收件箱)。
答案 1 :(得分:0)
我认为你应该阅读
MSDN: How to implement a producer / consumer dataflow pattern
我遇到了同样的问题:一个生产者生产了物品,而一些消费者消费它们并决定将它们发送给其他消费者。每个消费者都是异步工作,独立于其他消费者。
你的主要任务是制片人。他生产其他任务应该处理的项目。包含主任务代码的类具有以下功能:
public async Task ProduceOutputAsync(...)
您的主程序使用以下命令启动此任务:
var producerTask = Task.Run( () => MyProducer.ProduceOutputAsync(...)
一旦调用它,生产者任务就开始产生输出。与此同时,您的主程序可以继续做其他事情,例如启动消费者。
但是,让我们首先关注制作人任务。
生产者任务生成要由其他任务处理的类型T的项目。它们使用实现ITargetBlock'。
的对象转移到另一个任务每次生产者任务完成创建类型为T的对象时,它都会使用ITargetBlock.Post将其发送到目标块,或者最好是异步版本:
while (continueProducing())
{
T product = await CreateProduct(...)
bool accepted = await this.TargetBlock(product)
// process the return value
}
// if here, nothing to produce anymore. Notify the consumers:
this.TargetBlock.Complete();
制作人需要ITargetBlock <T
&gt;。在我的应用程序中,BufferBlock <T
&gt;够了。检查MSDN以获取其他可能的目标。
无论如何,数据流程块也应该实现ISourceBlock <T
&gt;。您的接收器等待输入到达源,获取并处理它。完成后,它可以将结果发送到它自己的目标块,并等待下一个输入,直到不再有预期的输入。当然,如果您的消费者没有产生输出,那么它就不必向目标发送任何东西。
等待输入如下:
ISourceBlock`<T`> mySource = ...;
while (await mySource.ReceiveAsync())
{ // a object of type T is available at the source
T objectToProcess = await mySource.ReceiveAsync();
// keep in mind that someone else might have fetched your object
// so only process it if you've got it.
if (objectToProcess != null)
{
await ProcessAsync(objectToProcess);
// if your processing produces output send the output to your target:
var myOutput = await ProduceOutput(objectToprocess);
await myTarget.SendAsync(myOutput);
}
}
// if here, no input expected anymore, notify my consumers:
myTarget.Complete();
每个消费者一听到就不再有任何输入就会停止。 完成所有任务后,您的主要功能可以读取结果并返回