TaskFactory内部任务从不执行,并且始终处于等待激活状态



我正在使用TaskFactory使用以下代码启动新任务。

var task = Task.Factory.StartNew(async () =>
{
    await Task.Run(() =>
    {
        // Do API Call
        var saveResponse = doAPICall();
    }).ConfigureAwait(false);
}).Unwrap();
task.Wait();

doAPICall((的代码如下所示,它调用一个返回Task的外部API。

private string doAPICall()
{
    Task<string> response = client.FindBags(request);
    response.Wait(60000);
    if (response.Status == TaskStatus.RanToCompletion)
    {
        return response.Result;
    }
}

doAPICall((函数中出现的问题是,任务"响应"状态从未更改为RanToCompletion,并且始终处于WaitingForActivation状态。我已经试着增加等待超时,但仍然没有成功。我使用TaskFactory而不是Task,因为将来我想创建自定义TaskFactory来更好地控制调度程序和并发性。

这是我在代码中缺少的东西吗?内部任务永远不会执行?

编辑我根据删除不必要的线程的注释修改了调用doAPICall((的代码,但仍然没有成功。:-(

var task = Task.Factory.StartNew(() =>
{
    // Do API Call
        var saveResponse = doAPICall();
});
task.Wait();

您当前使用的是sync over fake async over fake异步over sync over async。那真是一团糟。

遵循以下指南:

  1. 不要使用Task.Factory.StartNew。曾经I am using the TaskFactory instead of Task because of in future I want to create custom TaskFactory for more control over scheduler and concurrency.自定义任务调度器不能很好地处理异步代码。对于调度/并发,您可能需要采用更异步友好的解决方案。我的博客上有更多信息
  2. 不要阻塞异步代码。我看到两个Wait调用和一个Result调用,这两个调用都是严重的危险信号。我的博客上有更多信息
  3. 不要在生产代码中使用Task.Status。它可以用于调试,但您不应该在实际逻辑中使用它。总有更好的解决方案。我的博客上有更多信息
  4. 仅使用UI层中的Task.Run,而不嵌套在助手/库代码中。换句话说,使用它来调用方法,而不是实现的方法。我的博客上有更多信息

从最里面的方法开始工作:

private async Task<string> doAPICallAsync()
{
  Task<string> responseTask = client.FindBags(request);
  // Note: it would be far better to use a cancellation token here instead of a "timed wait".
  Task timeoutTask = Task.Delay(60000);
  Task completedTask = await Task.WhenAny(responseTask, timeoutTask);
  if (completedTask == responseTask)
    return await completedTask;
}

您的呼叫代码变为:

var saveResponse = await doAPICallAsync();

您将一个异步调用封装在一个同步调用中,然后封装在两个异步调用中。这就是方法,只需使用一个异步调用,您就可以了。

private Task<string> doAPICallAsync()
{
    return client.FindBags(request);
}

如果你需要在client.FindBags(request)之后做一些工作,请使用这个版本:

private async Task<string> doAPICallAsync()
{
    var result = await client.FindBags(request);
    var someNewResult = //do something with result
    return someNewResult;
}

然后这样称呼它:

var result = await doAPICallAsync();

如果你真的需要一个同步版本

private string doAPICall()
{
    return client.FindBags(request).Result;
}

这样称呼它:

var result = doAPICall();

如果可以的话,不要忘记在每次等待后添加ConfigureAwait(false)

相关内容

  • 没有找到相关文章

最新更新