将项目发布到TPL DataFlow
时,是否有任何机制可以允许延迟发布?
public partial class BasicDataFlowService
{
private readonly ActionBlock<string> workerBlock;
public BasicDataFlowService()
{
workerBlock = new ActionBlock<string>(file => DoWork(file), new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 32
});
}
partial void DoWork(string fileName);
private void AddToDataFlow(string file)
{
workerBlock.Post(file);
}
}
在AddToDataFlow
内,我希望能够在处理项目之前指定延迟(例如,如果我们决定将处理推迟30秒)。
我确实考虑过将TransFormBlock
与new System.Threading.ManualResetEvent(false).WaitOne(1000);
一起使用,例如
var requeueBlock = new TransformBlock<string, string>(file =>
{
new System.Threading.ManualResetEvent(false).WaitOne(1000);
return file;
});
requeueBlock.LinkTo(workerBlock);
然而,这似乎消耗了一个不必要的线程,可以被链中的其他块使用。
答案 0 :(得分:0)
首先,您需要将ManualResetEvent
存储为单身,否则所有线程都会有自己的对象等待,而您的方法将无法正常工作。
其次,如果您需要在管道中的AppDomain
内进行同步,请考虑ManualResetEventSlim
版本而不是重ManualResetEvent
。
如果您希望重用机器的内核而无需等待,您应该研究SpinWait
轻量级结构。在这种情况下,您可能会发现Joseph Albahari' article非常有用:
// singleton variable
bool _proceed;
var requeueBlock = new TransformBlock<string, string>(file =>
{
var spinWait = new SpinWait();
while (!_proceed)
{
// ensure we have the latest _proceed value
Thread.MemoryBarrier();
// try to spin for a while
// after some spins, yield to another thread
spinWait.SpinOnce();
}
return file;
});
答案 1 :(得分:0)
要在将值发布到workerBlock
之前添加延迟,您只需插入延迟并在发布值之前等待它。如果workerBlock
具有有限容量,您可以await SendAsync
。完成目标的几个选项:
private async Task AddToDataflow(string file, TimeSpan delay) {
await Task.Delay(delay);
await workerBlock.SendAsync(file);
}
private async Task AddToDataflow(string file) {
var delay = TimeSpan.FromSeconds(30);
await Task.Delay(delay);
await workerBlock.SendAsync(file);
}
private async void AddToDataflow(string file) {
var delay = TimeSpan.FromSeconds(30);
await Task.Delay(delay);
workerBlock.Post(file);
}