有没有一种巧妙的方法可以强制一堆"异步"C#代码单线程运行,就好像它实际上不是"异步"一样



假设(完全假设;)(我有一大堆async代码。

10 个类; 100 个异步方法,其中 10 个实际上是在做异步工作(例如,我们在哪里WriteToDbAsync(data)ReadFileFromInternetAsync(uri),或者当WhenAll(parallelTasks)时。

我想对它进行一堆诊断调试。我想对它进行性能分析,并手动浏览一堆以查看是什么。

我的所有工具都是围绕同步 C# 代码设计的。他们会使用async,但它肯定效率低得多,调试也更难,即使我尝试直接管理线程。

如果我只对代码的一小部分感兴趣,那么暂时取消async这部分代码肯定容易得多。同步读取和写入,并且只需按顺序对我的每个"并行"Task进行 Task.Wait((。但是,如果我想在大量代码中四处闲逛,这是不可行的。

有没有办法要求C#为我运行一些这样的"async"代码?

即某种(() => MyAsyncMethod()).RunAsThoughAsyncDidntExist(),它知道每当它与外界进行真正的异步通信时,它应该旋转(在同一线程内(,直到得到答案。每当它被要求并行运行代码时...不要;只需在其单线程上串联运行它们即可。等等。

我不是在谈论只是await完成任务,或者打电话给Task.Wait().这些不会改变该任务自身执行的方式


强烈认为这种东西不存在,我只需要忍受我的工具没有为async代码进行良好的架构。

但是,如果在该领域具有一定专业知识的人可以确认这一点,那就太好了。


编辑:(因为SO告诉我解释为什么这个建议不是答案(...Sinatr 建议这样做:如何创建自定义同步上下文,以便所有延续都可以由我自己的单线程事件循环处理? 但是(据我了解(这将确保每次有await命令时,之后的代码await继续在同一线程上。但我希望await的实际内容在同一线程上。

请记住,异步 != 并行。

  • 并行意味着同时运行两段或多段代码,这只能通过多线程来完成。这是关于代码如何运行
  • 异步代码释放当前线程,使其在等待其他操作时执行其他操作。这是关于代码如何等待

具有同步上下文的异步代码可以在单个线程上运行。它开始在一个线程上运行,然后触发 I/O 请求(如 HTTP 请求(,并且在等待时没有线程。然后,延续(因为存在同步上下文(可以在同一线程上发生,具体取决于同步上下文所需的内容,例如在 UI 应用程序中,延续发生在 UI 线程上。

如果没有同步上下文,则延续可以在任何 ThreadPool 线程上运行(但仍可能在同一线程上发生(。

因此,如果您的目标是使其最初运行,然后在同一线程上恢复所有内容,那么您已经提到的答案确实是最好的方法,因为正是该同步上下文决定了如何执行延续。

但是,如果有任何调用Task.Run,这将对您没有帮助,因为该方法的全部目的是启动一个新线程(并为您提供一种异步方法来等待该线程完成(。

如果代码在任何await调用中使用.ConfigureAwait(false),也可能无济于事,因为这明确表示"我不需要在同步上下文上恢复",因此它可能仍在 ThreadPool 线程上运行。我不知道斯蒂芬的解决方案是否对此有所帮助。

但是,如果您真的希望它"RunAsThoughAsyncDidntExist"并在等待时锁定当前线程,那么这是不可能的。以这段代码为例:

var myTask = DoSomethingAsync();
DoSomethingElse();
var results = await myTask;

此代码启动 I/O 请求,然后在等待该请求完成时执行其他操作,然后完成等待并处理结果。使其同步行为的唯一方法是重构它,因为同步代码在等待时无法执行其他工作。必须决定是在DoSomethingElse()之前还是之后执行 I/O 请求。

最新更新