C#多线程之取消架构介绍攻略
什么是C#多线程取消架构
在C#中,我们可以使用多线程来进行异步编程,但是在实际场景中,有时候由于各种原因,我们需要中途取消一个正在运行的线程。而为了达到这个目的,C#中引入了取消架构(Cancellation Framework),通过这个机制,我们可以实现对多线程操作的取消。在该机制中,我们创建一个CancellationTokenSource的实例,然后将它的Token对象传递给所有的任务,并在需要取消这些任务时,调用该Token对象的Cancel方法即可。
如何使用C#多线程取消架构
创建CancellationTokenSource实例
我们先创建一个CancellationTokenSource实例:
CancellationTokenSource cts = new CancellationTokenSource();
异步执行需要取消的任务
我们有一个需要被取消的异步任务,这个任务可能需要运行几秒钟或几分钟,我们可以使用Task.Run方法来启动这个任务,并将CancellationTokenSource的Token对象作为参数传入:
var task = Task.Run(() => {
// 执行需要被取消的任务
// 可以使用while循环来模拟一个长时间任务,这里使用Thread.Sleep来模拟
int i = 0;
while (true) {
if (cts.Token.IsCancellationRequested) {
break;
}
Console.WriteLine("Task is running: {0}", ++i);
Thread.Sleep(1000);
}
Console.WriteLine("Task is finished.");
}, cts.Token);
在该任务中,我们使用了while循环,并且在每次循环中都检测CancellationTokenSource的Token对象是否被取消,如果是,则跳出循环,结束任务。这里我们使用Thread.Sleep方法来模拟一个长时间运行的任务。
取消任务
当我们需要取消该异步任务时,可以直接调用CancellationTokenSource的Cancel方法即可:
cts.Cancel();
Cancel方法将会通知所有使用该Token对象的任务,并使这些任务停止运行。
检查任务是否被取消
我们也可以在任务中检查Token是否被取消,如果是,则立即停止任务:
for (int i = 0; i < 10; i++) {
if (cts.Token.IsCancellationRequested) {
Console.WriteLine("Task is cancelled.");
return;
}
Console.WriteLine("Task is running: {0}", i);
Thread.Sleep(1000);
}
Console.WriteLine("Task is finished.");
示例一:向多个URL异步请求数据
下面我们来看一个使用C#多线程取消架构的例子,假设我们需要从多个URL异步请求数据,并将它们合并到一个结果中:
async Task<string> GetDataAsync(string url, CancellationToken ct) {
using (HttpClient client = new HttpClient()) {
using (HttpResponseMessage response = await client.GetAsync(url, ct)) {
var data = await response.Content.ReadAsStringAsync();
return data;
}
}
}
async Task<string> GetDataFromUrlsAsync(string[] urls, CancellationToken ct) {
List<Task<string>> tasks = new List<Task<string>>();
foreach (string url in urls) {
tasks.Add(GetDataAsync(url, ct));
}
string[] result = await Task.WhenAll(tasks.ToArray());
return string.Join(",", result);
}
在该例子中,我们首先定义了一个GetDataAsync方法来异步获取指定URL的数据,该方法使用HttpClient来发起网络请求,并将获取到的数据返回。
然后我们定义了一个GetDataFromUrlsAsync方法来同时从多个URL请求数据,并将它们合并到一个结果中。在该方法中,我们使用List
最后我们调用该方法,并在需要取消请求时,调用CancellationTokenSource的Cancel方法:
CancellationTokenSource cts = new CancellationTokenSource();
string[] urls = new string[] { "http://url1.com", "http://url2.com", "http://url3.com" };
Task<string> task = GetDataFromUrlsAsync(urls, cts.Token);
cts.CancelAfter(TimeSpan.FromSeconds(5));
try {
string result = await task;
Console.WriteLine(result);
} catch (TaskCanceledException) {
Console.WriteLine("Task is cancelled.");
}
在该代码中,我们首先创建一个CancellationTokenSource实例,并将它的Token对象传递给GetDataFromUrlsAsync方法。然后我们调用该方法,使用string[]数组来保存需要请求的URL。
在调用方法后,我们使用cts.CancelAfter方法来5秒钟后自动取消请求,在等待方法返回的过程中,如果任务被取消,则会抛出TaskCanceledException异常,我们可以在catch块中处理这个异常。
示例二:使用Parallel.ForEach执行任务
在下面这个例子里,我们使用Parallel.ForEach方法来执行多个任务,而使用CancellationTokenSource来取消所有任务:
var cts = new CancellationTokenSource();
string[] urls = new string[] { "http://url1.com", "http://url2.com", "http://url3.com" };
try {
Parallel.ForEach(urls, new ParallelOptions { CancellationToken = cts.Token }, url => {
// 执行任务,这里使用HttpClient来请求数据
using (var client = new HttpClient()) {
var response = client.GetAsync(url, cts.Token).Result;
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}
});
} catch (OperationCanceledException) {
Console.WriteLine("Tasks are cancelled.");
}
在该例子中,我们使用Parallel.ForEach方法来并行执行多个任务,使用CancellationTokenSource的Token对象来取消所有任务。我们使用using语句来管理HttpClient的生命周期,并在任务中使用HttpClient来请求网络数据。
最后我们使用try-catch块来捕获OperationCanceledException异常,该异常会在任务被取消时抛出。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#多线程之取消架构介绍 - Python技术站