HttpClient的超时在异步块内不起作用

时间:2016-11-19 19:14:31

标签: asynchronous f# async-await c#-to-f# f#-async

我正在尝试使用HttpClient在F#中发送POST请求。不幸的是,我发现F#中的超时并不起作用。我有这样的代码:

let asyncTest() = async {
    let httpClient = new HttpClient()
    try 
        let! res = httpClient.PostAsync("http://135.128.223.112", new StringContent("test"), (new CancellationTokenSource(2000)).Token) |> Async.AwaitTask
        Console.WriteLine("Test 1")
    with 
        | :? Exception as e -> Console.WriteLine("Test 2")
} 

您可以在代码中看到的IP不存在。我希望在2秒后取消呼叫(取消令牌),但永远不会抛出异常("测试2"永远不会在屏幕上打印)。在PostAsync方法调用之后,程序控制永远不会返回到异步块。如果我使用HttpClient.Timeout属性或Async.Catch而不是try块,行为是相同的。

在C#中,在引发两秒异常后,相同的代码按预期工作:

private async Task Test()
{
    var httpClient = new HttpClient();
    await
            httpClient.PostAsync("http://135.128.223.112", new StringContent("test"),
                new CancellationTokenSource(2000).Token);
 }

我知道F#和C#中的异步是不同的,所以我希望这是由一些同步问题引起的,死锁......我希望有更深入了解F#async的人可以解释这个并提供解决方法。

更新: 我正在开始像这样的F#异步工作:

Async.Start (asyncTest())

我在控制台应用程序中运行此测试,最后我有ReadKey(),因此应用程序不会比异步更早结束。

在评论Fyodor评论后,我试图将其更改为RunSynchronously。现在异常被提出但我仍然需要它与Async.Start一起工作。

1 个答案:

答案 0 :(得分:5)

你所看到的是两件事的结果:

  1. OperationCancelledException通过取消延续使用F#异步中的特殊路径。在实践中,它意味着在async区块的背景下,它是一个无法捕获的"异常,绕过try-with,它适用于错误延续。
  2. AwaitTask整合您正在等待加入async广告资源的任务 - 其中包括将任务取消提升为异步取消(OperationCancelledException而不是{{1} })并降低整个工作流程。
  3. 这不是一个明显的行为,它似乎正在为F#的未来版本进行更改。

    与此同时,你可以尝试这样的事情,而不是TaskCancelledException

    Async.AwaitTask