假设(完全假设;)(我有一大堆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 请求。