c# - 如何在一段时间后停止异步任务
问题描述
我试图在一段时间后停止 C# 中的任务。
对于我的代码: Task.Delay().Wait() 应该只代表 Task 所做的一些工作。
我的代码:
public static void Main()
{
Console.WriteLine("starting app");
try
{
Console.WriteLine("before");
DoStuff(1000);
Console.WriteLine("after");
}
catch
{
Console.WriteLine("TIMEOUT");
}
Console.WriteLine("Main finished wait 5 sec now");
Task.Delay(10000).Wait();
Console.WriteLine("Closing app now");
}
public static async Task DoStuff(int time)
{
Task real = Task.Run(()=>
{
Task.Delay(2000).Wait();
Console.WriteLine("Task Running");
Task.Delay(2000).Wait();
Console.WriteLine("still running");
Task.Delay(2000).Wait();
Console.WriteLine("Not dead yet");
Task.Delay(1000).Wait();
Console.WriteLine("Task done");
Task.Delay(5000);
});
bool success = real.Wait(time);
if ( success )
{
Console.WriteLine("Task finished in time");
await real;
}
else
{
Console.WriteLine("Task did not finish");
real.Dispose();
throw new TimeoutException("The task took too long");
}
}
我已经尝试使用取消令牌,但我没有循环来检查每次迭代的令牌。所以我试着用 来做,Task.Wait(time)
我得到了正确的信息,但使用该Task.Dispose()
方法后任务并没有停止。我得到以下输出:
所以我得到了当前的输出,但任务继续在后面运行..关于如何解决这个问题的任何想法?
解决方案
首先:永远不要Wait()
做任务(除非你知道他们已经完成了);使用await
. 至于超时:CancellationTokenSource
可以设置为延时后超时,如下。
请注意,取消标记不会中断代码 - 您(或其他代码,如Task.Delay
)需要检查取消(例如,ThrowIfCancellationRequested()
),或者您需要Register(...)
添加一个回调,当它被调用时取消。
using System;
using System.Threading;
using System.Threading.Tasks;
static class P
{
public static async Task Main()
{
Console.WriteLine("starting app");
try
{
Console.WriteLine("before");
await DoStuffAsync(1000);
Console.WriteLine("after");
}
catch
{
Console.WriteLine("TIMEOUT");
}
Console.WriteLine("Main finished wait 5 sec now");
await Task.Delay(5000);
Console.WriteLine("Closing app now");
}
public static async Task DoStuffAsync(int time)
{
using var cts = new CancellationTokenSource(time); // assuming here that "time" is milliseconds
Task real = Task.Run(async () =>
{
await Task.Delay(2000, cts.Token);
Console.WriteLine("Task Running");
await Task.Delay(2000, cts.Token);
Console.WriteLine("still running");
await Task.Delay(2000, cts.Token);
Console.WriteLine("Not dead yet");
await Task.Delay(2000, cts.Token);
Console.WriteLine("Task done");
await Task.Delay(2000, cts.Token);
});
bool success;
try
{
await real;
success = true;
}
catch (OperationCanceledException)
{
success = false;
}
if (success)
{
Console.WriteLine("Task finished in time");
}
else
{
Console.WriteLine("Task tool too long");
}
}
}
请注意,您也可以将取消令牌传递给Task.Run
,但这只是在执行回调之前进行检查- 而且通常不会有明显的延迟,所以......通常不值得。
附加说明:如果您想确定取消的确切内容(即OperationCanceledException
来自cts
):
catch (OperationCanceledException cancel) when (cancel.CancellationToken == cts.Token)
推荐阅读
- postgresql - Amazon aurora postgres serverless:数据库返回超过允许的响应大小限制
- javascript - 如何使用 Express 后端向用户呈现反应页面?
- r - R如何根据2个条件修改数据框中的条目
- google-cloud-platform - 如何将文件从服务器上传到 Cloud Storage 存储分区?
- android - 自动填写不带国家代码的电话号码
- python - 根据熊猫中的今天日期和其他条件过滤数据框
- android - Flutter web的移动设备视图中的TextFormField宽度问题
- c - Visual Studio 2019:无法更改运行时库:错误“元素
具有无效值 /MDd " - java - Java - 给定字符串中的所有排列和组合
- php - url中的GET页面由于htaccess而加倍