【问题标题】:Using Microsoft.bcl.async in PCL with Mono Droid?在带有 Mono Droid 的 PCL 中使用 Microsoft.bcl.async?
【发布时间】:2013-01-31 17:37:40
【问题描述】:

我有一个针对 Profile158(Windows Store、.NET 4.5、Silverlight 5、Windows Phone 8)的可移植类库 (PCL)。我可以轻松地使用返回一种任务类型的方法,并且一切都按我的预期工作。每当我访问 Result 属性时,它都会完成异步代码的运行并返回结果。

但是,如果我在 PCL 内的方法中使用 async/await 关键字,我会返回一个任务。但是,当我尝试访问 Result 属性时,它会阻塞并且永远不会返回。

在两种情况下查看 Visual Studio 中的调试输出窗口,我看到相同的文本:

Thread started: 
Thread started: 
Loaded assembly: Mono.Security.dll [External]
Thread started: 
Thread started: 

所以看起来好像代码正在运行,但它永远不会返回到 UI 线程。有没有其他人尝试在 PCL 中使用带有 Microsoft.bcl.async 的 PCL?

我的 Mono Droid 项目针对的是 Android 2.1。

谢谢, ——约翰

更新:
以下是有关不同场景的一些附加信息。首先,这是在 UI 代码中编写时在 Mono Droid 上运行的代码:

var task = request.GetResponseAsync();
string html = task.Result.GetResponseText();

然后我在 PCL 中创建了以下方法:

public async Task<string> Test()
{
    IHttpResponse responce = await GetResponseAsync();
    return responce.GetResponseText();
}

并使用 Mono UI 代码中的以下代码调用它:

string html = request.Test().Result;

它永远不会回来......

【问题讨论】:

  • 如果您使用 Result 属性,它将阻塞直到任务完成。如果您从任务本身需要执行的同一个线程执行此操作,那么您基本上已经给自己一个死锁。目前还不清楚你的代码做了什么……你有一个简短但完整的程序来演示这个问题吗?
  • @dsplaisted 在 BUILD 的演示中使用了 MonoDroid 这一层 - channel9.msdn.com/Events/Build/2012/3-004 - 我将在这篇文章中添加 PCL 标签并发出蝙蝠信号 - 他将在雷德蒙德时间陪伴...
  • 与您的问题无关,但 Microsoft.Bcl.Async 仍处于测试阶段。应避免在任何生产代码中使用它。当然,您现在可能只是在测试它。
  • 我不是律师,所以请阅读许可证并自行决定,但我相信 Microsoft.Bcl.Async 的许可证将允许您在生产中使用它(我想您会称之为“上线”许可证)。风险是否值得由您决定。但是,它实际上没有许可用于非 Windows 平台。因此,您可以针对它编译您的可移植库,但是当它实际在 Android 上运行时,您将需要不同的实现。在我的 BUILD 演示中,我通过调整 AsyncBridge 代码来做到这一点。
  • 你不应该使用配置文件 104 而不是 158 吗??

标签: xamarin.android portable-class-library


【解决方案1】:

这是classic deadlock scenario,正如我在博客中描述的那样。

默认情况下,await 将捕获一个“上下文”并使用它来恢复async 方法。这个“上下文”是当前的SynchronizationContext,除非它是null,在这种情况下它是当前的TaskScheduler

因此,您正在从 UI 线程(提供 SynchronizationContext)调用 async 方法,然后通过调用 Result 阻塞 UI 线程。 async 方法无法完成,因为它试图在被阻塞的 UI 线程上完成。

要解决此问题,请遵循以下准则:

  1. 一直使用async。不要在从async 方法返回的Tasks 上调用ResultWait;请改用await
  2. 尽可能在您的库代码中使用ConfigureAwait(false)

您可能还会发现我的async/await intro 很有帮助。

【讨论】:

  • 我可以接受 UI 代码阻塞,直到操作完成。问题是它永远不会完成并且永远不会返回到 UI 线程。如果我从我的方法返回一个 Task 并且不使用 async/await,则 UI 代码会短暂阻塞,然后返回。我已经使用 Windows Phone 8 和 Windows Store 应用程序尝试了相同的 UI 代码,它们都正确返回到 UI 线程。我还检查以确保 SynchronizationContext 在 Android 中不为空,但事实并非如此。因此,使用 async/await 的 Android 和 PCL 似乎是导致问题的原因。
  • 所有 UI 都存在同样的死锁,包括 WP8 和 netcore。如果您有代码在 WP8 中的 async 方法上使用 Result 而没有死锁并且在 Android 中存在相同的精确代码死锁,那么请发布代码。
  • 您是说Test 代码在 WP8 和 Windows 应用商店上没有死锁吗?由于我的回答和博文中给出的原因,我当然希望出现僵局。
  • 我的错误。我再次查看了我的 WP8 代码,它使用 async 和 await,这就是它没有阻塞的原因。所以你的答案是绝对正确的。
  • 为了澄清我的回答,任何一个指南都可以防止僵局,但建议两者都
猜你喜欢
  • 2012-09-11
  • 2012-05-30
  • 1970-01-01
  • 1970-01-01
  • 2011-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多