c# - 在 c# 中正确使用取消令牌
问题描述
我最近接触了 C# 语言,并且正在努力从 cassandra 中获取数据,所以我正在使用下面的代码,该代码从 Cassandra 中获取数据并且工作正常。
我唯一的问题是我的ProcessCassQuery
方法 - 我正在传递CancellationToken.None
给我的requestExecuter
函数,这可能不是正确的做法。处理这种情况的正确方法应该是什么,我应该怎么做才能正确处理它?
/**
*
* Below method does multiple async calls on each table for their corresponding id's by limiting it down using Semaphore.
*
*/
private async Task<List<T>> ProcessCassQueries<T>(IList<int> ids, Func<CancellationToken, int, Task<T>> mapperFunc, string msg) where T : class
{
var tasks = ids.Select(async id =>
{
await semaphore.WaitAsync();
try
{
ProcessCassQuery(ct => mapperFunc(ct, id), msg);
}
finally
{
semaphore.Release();
}
});
return (await Task.WhenAll(tasks)).Where(e => e != null).ToList();
}
// this might not be good idea to do it. how can I improve below method?
private Task<T> ProcessCassQuery<T>(Func<CancellationToken, Task<T>> requestExecuter, string msg) where T : class
{
return requestExecuter(CancellationToken.None);
}
解决方案
正如官方文档中所说,取消令牌允许传播取消信号。这可能很有用,例如,取消由于某种原因不再有意义或耗时太长的长时间运行的操作。
这CancelationTokenSource
将允许您获得一个自定义令牌,您可以将其传递给requestExecutor
. 它还将提供取消运行的方法Task
。
private CancellationTokenSource cts = new CancellationTokenSource();
// ...
private Task<T> ProcessCassQuery<T>(Func<CancellationToken, Task<T>> requestExecuter, string msg) where T : class
{
return requestExecuter(cts.Token);
}
例子
让我们看一个不同的最小/虚拟示例,以便我们了解它的内部。
考虑以下方法,GetSomethingAsync
它将每秒返回一个递增的整数。
如果此过程被外部操作取消,调用 totoken.ThrowIfCancellationRequested
将确保抛出 a 。TaskCanceledException
可以采取其他方法,例如,检查是否token.IsCancellationRequested
为真并对其进行处理。
private static async IAsyncEnumerable<int> GetSomethingAsync(CancellationToken token)
{
Console.WriteLine("starting to get something");
token.ThrowIfCancellationRequested();
for (var i = 0; i < 100; i++)
{
await Task.Delay(1000, token);
yield return i;
}
Console.WriteLine("finished getting something");
}
现在让我们构建 main 方法来调用上述方法。
public static async Task Main()
{
var cts = new CancellationTokenSource();
// cancel it after 3 seconds, just for demo purposes
cts.CancelAfter(3000);
// or: Task.Delay(3000).ContinueWith(_ => { cts.Cancel(); });
await foreach (var i in GetSomethingAsync(cts.Token))
{
Console.WriteLine(i);
}
}
如果我们运行它,我们将得到如下所示的输出:
starting to get something
0
1
Unhandled exception. System.Threading.Tasks.TaskCanceledException: A task was canceled.
当然,这只是一个虚拟示例,取消可以由用户操作或发生的某些事件触发,它不必是计时器。
推荐阅读
- go - 将 Golang 日志输出设置为文件不会在函数声明之外持续存在
- actionscript-3 - 添加同一对象的多个实例
- javascript - 刷新页面并保持滚动位置
- kubernetes - Kubernetes Minikube 需要多少磁盘空间
- c++ - 为什么我们不能使用scanf直接初始化struct中的变量?
- wix - 如果出现 Windows Installer 错误 1704,如何停止基于 WiX 的静默安装
- ios - 为什么我的 iOS 应用程序启动屏幕在加载时消失然后重新出现?
- php - 删除过期会话
- angular6 - 为什么我的 Angular 6 httpClient POST 请求会触发两次
- shell - 在 mount 和 mkdir 之间循环