从同步上下文调用异步方法

2024-05-15

我在代码中通过 HTTP 调用服务(最终使用 HttpClient.SendAsync 方法)。然后从 WebAPI 控制器操作调用此代码。大多数情况下,它工作得很好(测试通过),但是当我在 IIS 上部署时,我遇到了死锁,因为异步方法调用的调用者已被阻止,并且在完成之前无法在该线程上继续(它不会) 。

虽然我可以使我的大部分方法异步,但我觉得我对何时必须这样做没有基本的了解。

例如,假设我确实使大部分方法异步(因为它们最终调用其他异步服务方法),如果我构建了一个消息循环,我想要对程度进行一些控制,那么我将如何调用程序的第一个异步方法并行性?

由于 HttpClient 没有任何同步方法,如果我有一个不存在的抽象,我可以安全地假设做什么async意识到的?我读过有关ConfigureAwait(false)但我不太明白它的作用。对我来说很奇怪的是它是在异步调用之后设置的。对我来说,这感觉就像是一场等待发生的比赛……尽管不太可能……

WebAPI 示例:

public HttpResponseMessage Get()
{
  var userContext = contextService.GetUserContext(); // <-- synchronous
  return ...
}

// Some IUserContextService implementation
public IUserContext GetUserContext()
{
  var httpClient = new HttpClient();
  var result = httpClient.GetAsync(...).Result; // <-- I really don't care if this is asynchronous or not
  return new HttpUserContext(result);
}

消息循环示例:

var mq = new MessageQueue();
// we then run say 8 tasks that do this
for (;;)
{
  var m = mq.Get();
  var c = GetCommand(m);
  c.InvokeAsync().Wait();
  m.Delete();
}

当您有一个允许并行发生的消息循环并且您有异步方法时,就有机会最大限度地减少延迟。基本上,在这种情况下我想要完成的是最大限度地减少延迟和空闲时间。尽管我实际上不确定如何调用与从队列中到达的消息关联的命令。

更具体地说,如果命令调用需要执行服务请求,会有延迟在可用于获取下一条消息的调用中。像这样的东西。我完全可以通过将事物包装在队列中并自己协调来完成此任务,但我希望看到这项工作只需要一些异步/等待的东西。


虽然我可以使我的大部分方法异步,但我觉得我对何时必须这样做没有基本的了解。

从最低级别开始。听起来您已经开始了,但如果您在最低级别寻找更多内容,那么经验法则是应该制作任何基于 I/O 的内容async (e.g., HttpClient).

然后就是重复的问题async感染。您想使用异步方法,因此您可以使用await。所以该方法必须是async。所以它的所有调用者都必须使用await,所以它们也必须是async, etc.

如果我构建了一个消息循环,我想要对并行度进行一些控制,那么我将如何调用程序的第一个异步方法?

让框架来负责这件事是最简单的。例如,您可以只返回Task<T>来自 WebAPI 操作,并且框架理解这一点。类似地,UI 应用程序也有一个内置的消息循环async会自然而然地配合。

如果遇到框架不理解的情况Task或者有一个内置的消息循环(通常是控制台应用程序或 Win32 服务),您可以使用AsyncContext输入我的AsyncEx library http://nitoasyncex.codeplex.com/wikipage?title=AsyncContext. AsyncContext只需安装一个“主循环”(与async) 到当前线程。

由于 HttpClient 没有任何同步方法,如果我有一个不支持异步的抽象,我可以安全地假设做什么?

正确的做法是改变抽象。不要尝试阻塞异步代码;我描述的是常见的死锁场景 http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html详细在我的博客上。

你可以通过创建来改变抽象async-友好的。例如,改变IUserContext IUserContextService.GetUserContext() to Task<IUserContext> IUserContextService.GetUserContextAsync().

我读过有关ConfigureAwait(false) 的内容,但我不太明白它的作用。对我来说很奇怪的是它是在异步调用之后设置的。

你可能会发现我的async intro http://blog.stephencleary.com/2012/02/async-and-await.html有帮助。我不会多说ConfigureAwait在这个答案中,因为我认为它并不直接适用于这个问题的一个好的解决方案(但我并不是说它不好;它实际上should除非你使用can't用它)。

请记住async是一个具有优先规则的运算符等等。一开始感觉很神奇,但实际上并没有那么神奇。这段代码:

var result = await httpClient.GetAsync(url).ConfigureAwait(false);

与此代码完全相同:

var asyncOperation = httpClient.GetAsync(url).ConfigureAwait(false);
var result = await asyncOperation;

通常没有竞争条件async代码是因为 - 即使该方法是异步- 也是顺序的。该方法可以暂停在await,并且在此之前不会恢复await完成。

当您有一个允许并行发生的消息循环并且您有异步方法时,就有机会最大限度地减少延迟。

这是您第二次提到“并行”“消息循环”,但我认为您真正想要的是让多个(异步)消费者在同一个队列中工作,对吗?这很容易做到async(请注意,在此示例中,单个线程上只有一个消息循环;当一切都是异步时,这通常就是您所需要的):

await tasks.WhenAll(ConsumerAsync(), ConsumerAsync(), ConsumerAsync());

async Task ConsumerAsync()
{
  for (;;) // TODO: consider a CancellationToken for orderly shutdown
  {
    var m = await mq.ReceiveAsync();
    var c = GetCommand(m);
    await c.InvokeAsync();
    m.Delete();
  }
}

// Extension method
public static Task<Message> ReceiveAsync(this MessageQueue mq)
{
  return Task<Message>.Factory.FromAsync(mq.BeginReceive, mq.EndReceive, null);
}

您可能还会感兴趣TPL数据流 http://msdn.microsoft.com/en-us/library/hh228603%28v=vs.110%29.aspx。 Dataflow 是一个能够理解并能够很好地工作的库async代码,并且内置了很好的并行选项。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从同步上下文调用异步方法 的相关文章

随机推荐

  • MySQL Workbench 忽略外键

    在处理 MySQL Workbench 中的 SQL 编辑器时 我偶然发现了一些奇怪的事情 其中 执行似乎忽略了外键约束 这是一个例子 create database testdb use testdb create table t1 te
  • Expression.Property 的 Expression.Convert 类型

    我正在尝试转换参数表达式 但在转换为值类型时遇到问题 下面是我的代码示例 public static MemberExpression ConvertToType ParameterExpression sourceParameter Pr
  • 重新打包存储库对于大型二进制文件有用吗?

    我正在尝试将大量历史记录从 Perforce 转换为 Git 并且一个文件夹 现在是 git 分支 包含大量大型二进制文件 我的问题是运行时内存不足git gc aggressive 我的主要问题是重新打包存储库是否可能对大型二进制文件产生
  • 让 MongoDB 在 Linux 上监听远程连接

    我已在 Windows 本地计算机上 上成功安装 MongoDB 作为服务 但现在我想将 MongoDb 移动到单独的服务器 所以我将 tarball 解压到网络上的虚拟服务器 运行 Linux 当我从本地计算机使用 PuTTY 连接到服务
  • 如果 pandas 数据框中的所有列都有空字符串,则删除行

    我有一个数据框如下 Name Age 0 Tom 20 1 nick 21 2 3 krish 19 4 jack 18 5 6 jill 26 7 nick 期望的输出是 Name Age 0 Tom 20 1 nick 21 3 kri
  • 自制木桶选项无法识别?

    我正在关注安装两个 Mac 实用程序的在线资源 http www economyofeffort com 2014 08 11 beyond ctrl remap make that c aps lock key useful http w
  • 将 Joda 时间段划分为所需大小的间隔?

    我有一个时间 周期 P 由开始时间 S 和结束时间 E 表示 我想将 P 分成大小为 D 的 C 个块 也就是说 P C D R 其中 R 是剩余时间或剩余时间 eg S NOW E 10 sec after NOW D 3 sec The
  • 如何通过 Mturk API 从沙箱上的 HIT 中获取结果

    我创建了一个 XML 文件来向 MTurk 发布问题 并且 HIT 在工作沙箱中可见 我的几个朋友甚至提交了对 HIT 的回复 但我无法查看此 HIT 的结果 这是我用来发布 HIT 的代码 import boto3 MTURK SANDB
  • Material Design Lite 与 AngularJS 的集成 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我知道角材料 https github com angular material这有助于实现在 Angular 单页应用程序中使用的 Mater
  • 如何退出项目?

    我找不到离开该项目的方法 该项目的所有者不是我 任何通过 IAM 执行此操作的尝试都不会成功 我希望该项目停止显示在我的帐户中 获得许可的项目成员resourcemanager projects setIamPolicy需要在项目上添加 删
  • 主目录 不允许下载媒体

    尝试将 PDF 文件保存在下载目录中 但之后getExternalStoragePublicDirectory在 Android Q 后完全弃用 无法将文件保存在 DCIM 或 Pictures 文件夹之外的任何其他位置 因为尝试在此处保存
  • 持久(基于磁盘)R 树(或 R* 树)

    R Tree 如何实现为持久性 基于磁盘 树 用于保存 R Tree 索引或保存叶值的文件的架构是什么 注意 此外 如何在这样的持久 R 树中执行插入 更新和删除操作 注释 II 我已经实现了具有批量加载功能的内存中 R 树 但我认为当我们
  • 在Delphi 7中,为什么我可以给const赋值?

    我将一些 Delphi 代码从一个项目复制到另一个项目 发现它在新项目中无法编译 但在旧项目中可以编译 代码看起来像这样 procedure TForm1 CalculateGP const Price money 0 begin Pric
  • 在执行 ASP.NET 的 Visual Studio 2008 中未声明“__o”

    在执行 ASP NET MVC 时 我在 Visual Studio 2008 中经常遇到这个恼人的错误 bug 未声明 o 问题是什么 我该如何解决 只需将其添加到页面顶部即可 所以现在我的 ASP Net 内容占位符如下所示
  • 从 Google 电子表格中的单元格获取 href 标记内的链接 (gspread)

    我正在使用 Python 模块 gspread 尝试从 Google 电子表格的单元格中提取 href 标记内的链接 我尝试了以下方法 并指出了他们的问题 worksheet acell B5 value 获取单元格文本 而不是 href
  • 使用按位运算符将两个整数相乘

    如何使用按位运算符将两个整数相乘 我找到了一个实现here http www csci csusb edu schubert tutorials csci313 w04 TB BoothTutorial pdf 有没有更好的方法来实现乘法
  • Img srcset 和尺寸属性

    我正在尝试制作一个简单的网站img标签 将使用新的srcset属性 主要思想是根据屏幕分辨率更改图像 src 工作示例 http pixelteam pl surprise some files index html 问题在于sizes 正
  • 角度代理配置不起作用

    我不明白我错在哪里 附 已经尝试通过这个答案修复但仍然不起作用 Angular CLI 代理到后端不起作用 https stackoverflow com questions 39809008 angular cli proxy to ba
  • 将策略应用到资源控制器

    我有一个CRUD资源定义通过Route resource User UserController 既然可以生成CRUDGates and Policies 有没有办法应用这样的Gate Policy 以便将相应的Gate Policy应用于
  • 从同步上下文调用异步方法

    我在代码中通过 HTTP 调用服务 最终使用 HttpClient SendAsync 方法 然后从 WebAPI 控制器操作调用此代码 大多数情况下 它工作得很好 测试通过 但是当我在 IIS 上部署时 我遇到了死锁 因为异步方法调用的调