Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何强制ActionBlock快速完成_C#_Cancellation_Tpl Dataflow - Fatal编程技术网

C# 如何强制ActionBlock快速完成

C# 如何强制ActionBlock快速完成,c#,cancellation,tpl-dataflow,C#,Cancellation,Tpl Dataflow,根据报告: 当数据流块当前未处理消息且已保证不再处理任何消息时,该数据流块被视为已完成 就我而言,这种行为并不理想。我希望能够随时取消作业,但处理每个操作都需要很长时间。因此,当我取消令牌时,效果不是立即的。我必须等待当前处理的项目完成。我无法直接取消操作,因为我使用的API是不可取消的。我可以做些什么使块忽略当前正在运行的操作并立即完成吗 这里有一个例子来说明我的问题。令牌在500毫秒后取消,每个操作的持续时间为1000毫秒: static async Task Main() { va

根据报告:

当数据流块当前未处理消息且已保证不再处理任何消息时,该数据流块被视为已完成

就我而言,这种行为并不理想。我希望能够随时取消作业,但处理每个操作都需要很长时间。因此,当我取消令牌时,效果不是立即的。我必须等待当前处理的项目完成。我无法直接取消操作,因为我使用的API是不可取消的。我可以做些什么使块忽略当前正在运行的操作并立即完成吗

这里有一个例子来说明我的问题。令牌在500毫秒后取消,每个操作的持续时间为1000毫秒:

static async Task Main()
{
    var cts = new CancellationTokenSource(500);
    var block = new ActionBlock<int>(async x =>
    {
        await Task.Delay(1000);
    }, new ExecutionDataflowBlockOptions() { CancellationToken = cts.Token });
    block.Post(1); // I must wait for this one to complete
    block.Post(2); // This one is ignored
    block.Complete();
    var stopwatch = Stopwatch.StartNew();
    try
    {
        await block.Completion;
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine($"Canceled after {stopwatch.ElapsedMilliseconds} msec");
    }
}
static async Task Main()
{
var cts=新的CancellationTokenSource(500);
var block=新操作块(异步x=>
{
等待任务。延迟(1000);
},新的ExecutionDataflowBlockOptions(){CancellationToken=cts.Token});
block.Post(1);//我必须等待这一个完成
block.Post(2);//忽略此项
block.Complete();
var stopwatch=stopwatch.StartNew();
尝试
{
等待区块完成;
}
捕获(操作取消异常)
{
Console.WriteLine($“在{stopwatch.elapsedmillesons}毫秒后取消”);
}
}
输出:

1035毫秒后取消


所需的输出将在约500毫秒后取消。

根据您评论中的摘录…:

我希望在取消请求的情况下忽略当前正在运行的工作项。我已经不在乎了,那我为什么还要等呢

…并且假设您确实同意让任务继续运行,您只需将希望调用的作业包装到另一个任务中,该任务将持续轮询取消或完成,然后取消该
任务
。请看下面的“概念验证”代码,它将一个“长期运行”的任务包装在另一个“任务”中,并不断轮询包装好的任务以完成,以及一个用于取消的CancellationToken(完全是“一时冲动”状态,您当然要对其进行重新调整):

公共类LongRunningTaskSource
{
公共任务长时间运行(整数毫秒)
{
返回任务。运行(()=>
{
Console.WriteLine(“启动长时间运行的任务”);
睡眠(3000);
Console.WriteLine(“已完成长时间运行的任务”);
});
}
公共任务LongRunningTaskWrapper(整数毫秒,CancellationToken令牌)
{
任务=长时间运行(毫秒);
任务包装器任务=任务。运行(()=>
{
while(true)
{
//检查完成情况(当然,你可以做不同的事情
//取决于它是故障的还是完成的)。
如果(!(task.Status==TaskStatus.Running))
打破
//检查是否取消。
if(令牌.IsCancellationRequested)
{
WriteLine(“中止任务”);
token.ThrowIfCancellationRequested();
}
}
},代币);
返回包装器任务;
}
}
使用以下代码:

static void Main()
{
LongRunningTaskSource longRunning=新的LongRunningTaskSource();
CancellationTokenSource cts=新的CancellationTokenSource(1500);
Task Task=longRunning.LongRunningTaskWrapper(3000,cts.Token);
//睡足够长的时间,让事情自行发展。
睡眠(5000);
控制台写入线(“结束主”);
}
…生成以下输出:

Starting long running task
Aborting Task.
Exception thrown: 'System.OperationCanceledException' in mscorlib.dll
Finished long running task
Ended Main
Starting long running task
Finished long running task
Ended Main
包装好的任务显然在它自己的好时间内完成。如果你的没有问题,这通常是的情况,希望这能满足你的需要

作为补充示例,运行以下代码(让包装的任务在超时之前完成):

static void Main()
{
LongRunningTaskSource longRunning=新的LongRunningTaskSource();
CancellationTokenSource cts=新的CancellationTokenSource(3000);
Task Task=longRunning.LongRunningTaskWrapper(1500,cts.Token);
//睡足够长的时间,让事情自行发展。
睡眠(5000);
控制台写入线(“结束主”);
}
…生成以下输出:

Starting long running task
Aborting Task.
Exception thrown: 'System.OperationCanceledException' in mscorlib.dll
Finished long running task
Ended Main
Starting long running task
Finished long running task
Ended Main
因此,任务在超时之前开始并完成,不需要取消任何操作。当然,等待时没有任何东西被阻止。当然,正如您可能已经知道的那样,如果您知道长期运行的代码中后台使用的是什么,那么在必要时进行清理将是一件好事

希望您可以修改这个示例,将类似的内容传递给ActionBlock

免责声明和说明
我不熟悉TPL数据流库,所以这当然只是一个解决方法。此外,如果您所拥有的只是一个同步方法调用,而您对它没有任何影响,那么您显然需要两个任务。一个包装器任务用于包装同步调用,另一个包装器任务用于包装包装器任务,以包括连续状态轮询和取消检查。

您要求的是
线程。中止
行为,而不是取消。第三方物流与合作取消相反。这对于避免泄漏和同步问题是必要的。如果要取消延迟,请向其传递CancellationToken。如果您希望管道中的所有块突然取消,请将CancellationToken传递给所有块。我没有否决投票,但您试图以不应该使用的方式使用库。您不需要这样做-数据流来自于,一个机器人平台-