Await停止执行线程并且永远不会继续

时间:2015-03-25 17:31:21

标签: c# winforms asynchronous async-await

我有以下内容:

public async Task<bool> SearchForUpdatesAsync()
{
    return await TaskEx.Run(() =>
    {
    if (!ConnectionChecker.IsConnectionAvailable())
        return false;

    // Check for SSL and ignore it
    ServicePointManager.ServerCertificateValidationCallback += delegate { return (true); };

    var configurations = UpdateConfiguration.Download(UpdateConfigurationFileUri, Proxy);
    var result = new UpdateResult(configurations, CurrentVersion,
        IncludeAlpha, IncludeBeta);

    if (!result.UpdatesFound)
        return false;

    _updateConfigurations = result.NewestConfigurations;
    double updatePackageSize = 0;
    foreach (var updateConfiguration in _updateConfigurations)
    {
        var newPackageSize = GetUpdatePackageSize(updateConfiguration.UpdatePackageUri);
        if (newPackageSize == null)
            throw new SizeCalculationException(_lp.PackageSizeCalculationExceptionText);

        updatePackageSize += newPackageSize.Value;
        _packageOperations.Add(new UpdateVersion(updateConfiguration.LiteralVersion),
            updateConfiguration.Operations);
    }

    TotalSize = updatePackageSize;
    return true;
});
}

如您所见,我正在使用 Microsoft.Bcl 。 现在在我的其他课程中,我用正常的 void

编写了这段代码
TaskEx.Run(async delegate
{
    // ...
    _updateAvailable = await _updateManager.SearchForUpdatesAsync();
     MessageBox.Show("Test");
});

我遇到的问题是它执行_updateAvailable = await _updateManager.SearchForUpdatesAsync();然后它不会继续该线程,它只是停止,好像在该调用之后没有任何内容。一段时间后,Visual Studio也会告诉我:Thread ... exited with code 259,所以似乎还有一些东西存在。

我通过它进行调试以搜索可能被吞下的任何异常,但没有,一切正常并且执行返回 - 陈述。 这就是我不明白的地方,我从未看到MessageBox和/或没有代码超出此行的执行。 在我和一些朋友交谈后,他们确认不应该这样做。在实现async-await时我犯了一个可怕的错误吗?

在此先感谢,实际上我只能说这个,我没有更多的信息,我尽可能地感谢任何提示和帮助。

2 个答案:

答案 0 :(得分:5)

您遇到的主要问题是您在TaskEx.Run()中不必要地包装了您的方法,并且您可能在某处遇到了死锁。

您的方法签名目前是:

public async Task<bool> SearchForUpdatesAsync()

这意味着以下内容:

  

async - &gt;实际上没有做任何事情,但提供了一个“抬头”,可以在此方法中调用await,并且此方法可以用作可运行的任务。
   Task - &gt;此方法返回可在线程池上异步运行的可运行任务    <bool> - &gt;这个方法实际上在等待时返回bool。

await TaskEx.Run()是不必要的,因为这表示运行此方法,然后在值可用之后才返回。这很可能导致同步问题。删除此构造将使您的方法正常工作,但是您会注意到现在您没有理由甚至包括async运算符或Task<T>部分,因为该方法实际上是同步的。通常,如果您要在方法签名上调用async,那么您只会在方法签名上使用await标识符。

相反,您有两种选择。

  1. 每当您想要调用SearchForUpdates()时,您可以将其包装在Task<bool>.Run()中以异步方式运行(或等效的Bcl)
  2. 由于您使用的是WinForms,因此最好使用BackgroundWorker并在其中调用此方法。
  3. 关于使用async-await模式,我认为这是一篇很好的文章,可用于确保您遵循最佳实践:https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

答案 1 :(得分:1)

最佳做法是在图层中一直保持异步,然后在最终使用网站上调用等待或不太理想的 .Wait()/ .Result

此外,尝试将UI调用与后端工作分开,因为您可能会遇到同步/线程上下文问题。

public class WinFormsCode
{
    private async Task WinsFormCodeBehindMethodAsync()
    {
        var updatesAvailable = await _updateManager.SearchForUpdatesAsync();
        MessageBox.Show("Updates Available: " + updatesAvailable.ToString());
    }

    private void WinsFormCodeBehindMethodSync()
    {
        var updatesAvailable = _updateManager.SearchForUpdatesAsync().Result;
        MessageBox.Show("Updates Available: " + updatesAvailable.ToString());
    }
}

public class UpdateManager
{
    public async Task<bool> SearchForUpdatesAsync()
    {
        return true;
    }
}