为什么原来的任务在 ContinueWith else 时被取消了?
Why is the original task canceled when it ContinueWith something else?
我开始学习 C# 编程已经 4 周了。很好玩,但是,我的屁股很痛:
当我单独使用 HttpClient.PostAsync()
启动任务时,它工作正常。但如果我继续做其他事情,原来的任务将被取消,而不是被我取消。任务似乎对继续进行不满意。
Task<HttpResponseMessage> task0;
Task task1;
using (var client = new HttpClient())
{
HttpContent content = new ByteArrayContent(new byte[]{});
task0 = client.PostAsync("<valid http address>", content);
task1 = task0.ContinueWith((t) =>
{
// Do nothing
});
}
task1.Wait();
// I got task0.IsCanceled == true here
我试过了:
1,在PostAsync()
后立即添加task0.wait()
可以解决问题,但这不是我想要的。因为我需要从异步中获得性能优势,这样做会使它完全同步。
2、在task1.wait()
前加task0.wait()
会造成TaskCanceledExcpetion
.
3、去掉task1
等待task0
即可。
4、调用task0.start()
会得到"Start may not be called on a promise-style task."
所以,有人告诉我我做错了什么吗?
PS:
在我问这个问题之前,我已经用谷歌搜索了好几天。来自 Whosebug 的一些问题可能看起来相关,但事实证明它们与我的不一样。
Who canceled my Task? She/He 询问为什么没有执行延续任务。
Why does TaskCanceledException occur? She/He 弄乱了我从未做过的 CancellationToken,并得到了意想不到的结果。
我也读过这个 Task Cancellation 但仍然没有任何线索。
您的 HttpClient
很可能在 PostAsync
完成之前就已处理完毕。出于测试目的删除 using
语句,一切都会按预期工作。请求完成后,您应该在不同的时间处理您的客户。
此外,如果您的应用程序逻辑允许,许多人会建议尽可能重用 HttpClient
的单个实例。
因此,此代码似乎在您连接延续后立即处理 HttpClient
,这很可能不是您想要的。
如果要使用using
语句来处理客户端实例,则需要使用async
和await
关键字。以下代码等同于您的示例,编译器为您连接了延续。
public async Task FooAsync()
{
using (var client = new HttpClient())
{
HttpContent content = new ByteArrayContent(new byte[]{});
await client.PostAsync("<valid http address>", content);
// Continue your code here.
}
}
如果你想继续使用在没有编译器帮助的情况下创建的continuations,你可以将处理逻辑放在continuation中:
Task<HttpResponseMessage> task0;
Task task1;
var client = new HttpClient();
HttpContent content = new ByteArrayContent(new byte[]{});
task0 = client.PostAsync("<valid http address>", content);
task1 = task0.ContinueWith((t) =>
{
client.Dispose();
})
task1.Wait();
我开始学习 C# 编程已经 4 周了。很好玩,但是,我的屁股很痛:
当我单独使用 HttpClient.PostAsync()
启动任务时,它工作正常。但如果我继续做其他事情,原来的任务将被取消,而不是被我取消。任务似乎对继续进行不满意。
Task<HttpResponseMessage> task0;
Task task1;
using (var client = new HttpClient())
{
HttpContent content = new ByteArrayContent(new byte[]{});
task0 = client.PostAsync("<valid http address>", content);
task1 = task0.ContinueWith((t) =>
{
// Do nothing
});
}
task1.Wait();
// I got task0.IsCanceled == true here
我试过了:
1,在PostAsync()
后立即添加task0.wait()
可以解决问题,但这不是我想要的。因为我需要从异步中获得性能优势,这样做会使它完全同步。
2、在task1.wait()
前加task0.wait()
会造成TaskCanceledExcpetion
.
3、去掉task1
等待task0
即可。
4、调用task0.start()
会得到"Start may not be called on a promise-style task."
所以,有人告诉我我做错了什么吗?
PS:
在我问这个问题之前,我已经用谷歌搜索了好几天。来自 Whosebug 的一些问题可能看起来相关,但事实证明它们与我的不一样。
Who canceled my Task? She/He 询问为什么没有执行延续任务。
Why does TaskCanceledException occur? She/He 弄乱了我从未做过的 CancellationToken,并得到了意想不到的结果。
我也读过这个 Task Cancellation 但仍然没有任何线索。
您的 HttpClient
很可能在 PostAsync
完成之前就已处理完毕。出于测试目的删除 using
语句,一切都会按预期工作。请求完成后,您应该在不同的时间处理您的客户。
此外,如果您的应用程序逻辑允许,许多人会建议尽可能重用 HttpClient
的单个实例。
因此,此代码似乎在您连接延续后立即处理 HttpClient
,这很可能不是您想要的。
如果要使用using
语句来处理客户端实例,则需要使用async
和await
关键字。以下代码等同于您的示例,编译器为您连接了延续。
public async Task FooAsync()
{
using (var client = new HttpClient())
{
HttpContent content = new ByteArrayContent(new byte[]{});
await client.PostAsync("<valid http address>", content);
// Continue your code here.
}
}
如果你想继续使用在没有编译器帮助的情况下创建的continuations,你可以将处理逻辑放在continuation中:
Task<HttpResponseMessage> task0;
Task task1;
var client = new HttpClient();
HttpContent content = new ByteArrayContent(new byte[]{});
task0 = client.PostAsync("<valid http address>", content);
task1 = task0.ContinueWith((t) =>
{
client.Dispose();
})
task1.Wait();