Her*_*eld 0 .net c# asynchronous task-parallel-library
我有一种情况,我必须同步调用异步方法,并按如下方式完成:
obj.asyncMethod().Wait(myCancelToken)
Run Code Online (Sandbox Code Playgroud)
如果取消令牌被切换,则尽管通过using语句激活,但任务中的一次性物品将不会被处置.
以下程序说明了问题:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace LeakTest {
class Program {
static void Main(string[] args) {
try {
var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
LongRunningTask().Wait(timeout.Token);
} catch (OperationCanceledException error) {
// handling timeout is logically okay, but expect nothing to be leaked
}
Console.WriteLine("Leaked Instances = {0}", DisposableResource.Instances);
Console.ReadKey();
}
static async Task LongRunningTask() {
using (var resource = new DisposableResource()) {
await Task.Run( () => Thread.Sleep(1000));
}
}
public class DisposableResource : IDisposable {
public static int Instances = 0;
public DisposableResource() {
Instances++;
}
public void Dispose() {
Instances--;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
似乎Wait方法只是在取消时杀死任务线程,而不是在该线程内触发异常并让它自然终止.问题是为什么?
您已经取消了返回的任务,Wait(timeout.Token)
而不是返回的任务LongRunningTask
,如果您想要取消该令牌Task.Run
并将令牌传递给并且也使用await Task.Delay
而不是Thread.Sleep
在那里传递令牌.
static void Main(string[] args)
{
try
{
var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
LongRunningTask(timeout.Token).Wait();
}
catch (AggregateException error)
{
// handling timeout is logically okay, but expect nothing to be leaked
}
Console.WriteLine("Leaked Instances = {0}", DisposableResource.Instances);
Console.ReadLine();
}
static async Task LongRunningTask(CancellationToken token)
{
using (var resource = new DisposableResource())
{
await Task.Run(async () => await Task.Delay(1000, token), token);
}
}
public class DisposableResource : IDisposable
{
public static int Instances = 0;
public DisposableResource()
{
Instances++;
}
public void Dispose()
{
Instances--;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,一旦长时间运行的操作完成,using statment仍将处置资源.运行此示例:
static void Main(string[] args)
{
try {
var timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(100));
LongRunningTask().Wait(timeout.Token);
} catch (OperationCanceledException error) {
// handling timeout is logically okay, but expect nothing to be leaked
}
Console.WriteLine("Leaked Instances = {0}", DisposableResource.Instances);
Console.ReadKey();
}
static async Task LongRunningTask()
{
using (var resource = new DisposableResource())
{
await Task.Run(() => Thread.Sleep(1000));
}
}
public class DisposableResource : IDisposable
{
public static int Instances = 0;
public DisposableResource()
{
Instances++;
}
public void Dispose()
{
Instances--;
Console.WriteLine("Disposed resource. Leaked Instances = {0}", Instances);
}
}
Run Code Online (Sandbox Code Playgroud)
输出
泄漏实例= 1
处置资源.泄漏的实例= 0
归档时间: |
|
查看次数: |
830 次 |
最近记录: |