我尝试使用如下所示的超时编写一个简单的异步写入,并期望该函数在给定非常大的缓冲区和小waitTime时抛出TaskCanceledException。但是,这不会发生。 WriteAsync将阻塞很多秒,直到写入完成。我错过了什么?
public async void WriteWithTimeout(Stream os, byte[] buf, int waitMs)
{
CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds.
await os.WriteAsync(buf, 0, buf.Length, tokenSource.Token);
return;
}
从GUI线程调用:
try
{
WriteWithTimeout(response.OutputStream, buf100M, w1ms);
}
catch(OperationCanceledException e)
{
ConsoleWriteLine("Failed with exception: {0}", e.Message);
}
答案 0 :(得分:10)
你无法捕获异步空白。它必须返回一个任务,你必须等待它。
public async Task WriteWithTimeout(Stream os, byte[] buf, int waitMs)
{
CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds.
await os.WriteAsync(buf, 0, buf.Length, tokenSource.Token);
return;
}
gui code
try
{
await WriteWithTimeout(response.OutputStream, buf100M, w1ms);
}
catch(OperationCanceledException e)
{
ConsoleWriteLine("Failed with exception: {0}", e.Message);
}
取消仍然会发生,但你只是不遵守它们。
更新
os.WriteAsync(
可能仅仅是由幕后 1 的Task.Run(
支持的同步完成。取消令牌不会取消已经运行的Task.Run(
。在这种情况下,最好的方法是将取消包装在Task.WhenAny(
中,并通过无限长Task.Delay(
将令牌传递到那里。
public async Task WriteWithTimeout(Stream os, byte[] buf, int waitMs)
{
CancellationTokenSource tokenSource = new CancellationTokenSource(waitMs); // cancel after waitMs milliseconds.
var task = os.WriteAsync(buf, 0, buf.Length, tokenSource.Token);
var waitedTask = await Task.WhenAny(task, Task.Delay(-1, token));
await waitedTask; //Wait on the returned task to observe any exceptions.
}
1。例如,如果您未将FileStream
传递给构造函数,那么这是FileOptions.Asynchronous
的默认行为