为什么在继续使用其他内容时取消原始任务?

时间:2015-04-14 15:26:13

标签: c# .net task-parallel-library task

自从我潜入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,在task0.wait()之后立即添加PostAsync()将解决问题,但这不是我想要的。因为我需要异步的性能优势并且这样做会使它完全同步。

2,在task0.wait()之前添加task1.wait()会导致TaskCanceledExcpetion

3,删除task1并等待task0即可。

4,调用task0.start()将得到&#34;启动可能不会在承诺式任务上被调用。&#34;

所以,有人告诉我,我做错了什么?

PS:

在我问这个问题之前,我用Google搜索了好几天。 StackOverflow的一些问题看起来可能相关,但事实证明它们与我的不一样。

Who canceled my Task?她/他在问为什么继续任务没有被执行。

Why does TaskCanceledException occur?她/他搞砸了我从未做过的取消令,并得到了意想不到的结果。

我也读过这个Task Cancellation但仍然没有任何线索。

2 个答案:

答案 0 :(得分:7)

您的HttpClient最有可能在PostAsync完成之前被处理掉。删除using语句用于测试目的,一切都将按预期工作。当请求完成时,您应该将您的客户端部署在不同的位置。

此外,如果您的应用程序逻辑允许,许多人会建议尽可能多地重用HttpClient的单个实例。

答案 1 :(得分:5)

所以,这个代码似乎在你连接延续时就处理HttpClient,这很可能不是你想要的。

如果要使用using语句来处置客户端实例,则需要使用asyncawait关键字。以下代码等同于您的示例,编译器会为您提供延续。

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.
    }
}

如果你想继续使用在没有编译器帮助的情况下创建的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();