- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
背景
Async / Await通过自动创建“状态机”来促进.NET中响应式应用程序的使用,即使执行阻塞工作,该应用程序的主线程也可以保持响应式。
Windows Forms,WPF和ASP.NET(据我所知)都包含一种SynchronizationContext形式(尽管ASP.NET最近可能已删除了它;我并不肯定,因为我不使用它。)
最近,我需要扩展Windows Forms应用程序以支持从命令行接受参数,并且这样做时发现Async / Await停止了工作。在我的应用程序中执行了一些(几乎是随机的)步骤后,它要么挂起,要么返回到错误的点,从而有效地停止了运行。
同步上下文
经过研究,我发现在幕后,Async / Await依靠SynchronizationContext有效地处理路由机器状态(如上所述)。目前尚不清楚没有SynchronizationContext会发生什么情况:Stephen Toub(在他的博客文章
Stephen继续讲解“ AsyncPump.cs”,这是他的用于为控制台应用程序实现SynchronizationContext的类,并且到目前为止,在测试AsyncPump方面已经取得了成功。
问题
斯蒂芬的职位是2012年;还有其他解决方案吗?也许他的AsyncPump类已集成(和/或修改)到最新版本的.NET中?我宁愿使用一个库指定的等效项(如果有的话),这样,如果Async / Await的幕后实现发生任何更改,它也将自动更新,就像WindowsFormsSynchronizationContext一样。
我可以安全地使用WindowsFormsSynchronizationContext吗?在Program.cs中,我正在确定是否要实例化并打开一个Form,使用Application.Run()这样做,它会自动为我处理SynchronizationContext的设置(以及消息泵等)。我尝试实例化WindowsFormsSynchronizationContext并使用SynchronizationContext.SetSynchronizationContext()在我的主线程上进行设置,尽管可以编译,但我遇到的问题与根本没有SynchronizationContext时一样。
我正在寻找在控制台应用程序中支持Async / Await的最佳实践,因为(据我所知)它肯定需要SynchronizationContext才能正确执行。
编辑1:添加伪代码以帮助说明这种情况
如果我的程序收到了多个参数,则假定已从命令提示符处调用了它,并创建了一个自定义“ MyCustomConsole”类,该类使用P / Invoke Win32来调用AttachConsole(-1)。此时,由于我的程序是一个控制台应用程序,因此可以从CLI读取/写入。如果没有收到任何其他参数,则可以按预期启动Windows Form GUI(“ Application.Run(new Form1());”)。
问题是我最终调用以执行阻止操作的代码(“ RunBlockingOperationsAsync()”)是Async / Await以便保持响应,并且在通过GUI调用(通过“ Application.Run()”)时可以正常工作。如果我尝试在不带“ Application.Run()”的情况下调用“ RunBlockingOperationsAsync”,则该程序在调试时会死锁或跳转到意外区域,从而导致崩溃。
我尝试实现WindowsFormsSynchronizationContext,但是以相同的方式失败。但是,利用Stephen Toub的“ AsyncPump.cs”解决方案可以解决此问题(请参见下文)。
为此必须有一个内置的.NET框架,对吗?我不敢相信如果没有控制台应用程序的默认实现,那么Async / Await可以如此彻底地实现。我目前的理解是,没有Stephen的“ AsyncPump.cs”类(或类似类)的控制台应用程序中的Async / Await利用率将无法正常执行;有效地,这使得默认情况下在控制台应用程序中使用Async / Await不可用。
似乎控制台应用程序应具有等效版本的“ Application.Run()”,该版本将初始化适当的SynchronizationContext(以及可能需要的其他任何内容,现在可能什么也没有。)
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading; // <-- Note that System.Threading is required for SynchronizationContext.
namespace WindowsFormsApp1
{
static class Program
{
/// <summary>
/// The main entry point for the application—NOTE this is the default WinForms implementation for 'Program.cs'.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainAsync();
}
private static async Task MainAsync()
{
// If the application has received more than one argument, assume it's been invoked from the Command Prompt.
if (Environment.GetCommandLineArgs().Count() > 1)
{
using (MyCustomConsole mcc = new MyCustomConsole())
{
SynchronizationContext sctx = SynchronizationContext.Current; // <-- Initializes sctx to NULL, as at this point in the program,
// there is no SynchronizationContext. It is initialized when
// "Application.Run()" is invoked.
// Doesn't work (no SynchronizationContext):
await mcc.Run(); // <-- If the MyCustomConsole class is invoked without using AsyncPump.cs,
// it has no SynchronizationContext, and without it, Async/Await operations can
// execute on any thread from the ThreadPool, which causes deadlocks and jumping
// (almost at random?) to unexpected parts of my program, which I can only attribute
// to the size of the program and including numerous nested Async/Await calls, depending
// on what the program is trying to do.
// Perhaps instantiate a WindowsFormsSynchronizationContext and use it?
SynchronizationContext.SetSynchronizationContext = new WindowsFormsSynchronizationContext();
await mcc.Run(); // <-- Also fails in the same manner as above, despite having a SynchronizationContext.
// I don't understand why.
AsyncPump.Run(async () => { await mcc.Run(); }); // <-- This works. AsyncPump.cs is the custom SynchronizationContext that
// Stephen Toub provided in his blog. It not only handles SynchronizationContext,
// but sets itself as the SynchronizationContext for the current thread, which
// is required for Async/Await to operate with thread affinity.
}
}
else // Otherwise, display the main form and operate with a GUI.
{
Application.Run(new Form1()); // <-- Application.Run() instantiates a WindowsFormsSynchronizationContext,
// (amongst other things, like a message pump) and this is vital to a proper
// Async/Await machine state that requires thread affinity.
}
}
}
}
最佳答案
在没有同步上下文的情况下(或使用默认的SyncrhonizationContext
时),await
延续通常可以同步运行,即在其先前任务已结束的同一线程上运行。这可能导致模糊的死锁,这是.NET Framework 4.6中引入TaskContinuationOptions.RunContinuationsAsynchronously
的原因之一。有关更多详细信息和示例,请查看此博客文章:The danger of TaskCompletionSource class。AsyncPump
阻止代码挂起的事实表明您在mcc.Run()
内部可能存在类似情况。由于AsyncPump
对await
延续施加了真正的异步性(尽管在同一线程上),因此减少了发生死锁的机会。
就是说,我不建议使用AsyncPump
或WindowsFormsSynchronizationContext
作为解决方法。相反,您应该尝试找出导致代码挂起的确切原因(以及挂起的位置),然后在本地解决该问题,例如只需用Task.Run
包装有问题的电话。
我可以在您的代码中发现的另一个问题是,您不必等待或等待MainAsync
返回的任务。因此,至少对于逻辑的控制台分支(尤其是不使用AsyncPump
的情况),您的程序可能会过早地结束,具体取决于mcc.Run()
中的内容,并且您可能会让某些异常不被观察到。
关于c# - 调用Application.Run()或实例化WinForms UserControl对象时,在.NET Console中使用Async/Await中断应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57579612/
我有带皮肤的 DNN。我的 head 标签有 runat="server"所以我尝试在 head 标签内添加一个标签 "> 在后面的代码中,我在属性中设置了 var GoogleAPIkey。问题是它
我在 Node.JS 中有一个导出模块 exports.doSomethingImportant= function(req, res) { var id = req.params.id; Demo.
我是 F# 的新手,我一直在阅读 F# for Fun and Profit。在为什么使用 F#? 系列中,有一个 post描述异步代码。我遇到了 Async.StartChild函数,我不明白为什么
File 中有一堆相当方便的方法类,如 ReadAll***/WriteAll***/AppendAll***。 我遇到过很多情况,当我需要它们的异步对应物时,但它们根本不存在。 为什么?有什么陷阱吗
我最近开始做一个 Node 项目,并且一直在使用 async 库。我有点困惑哪个选项会更快。在某些数据上使用 async.map 并获取其结果,或使用 async.each 迭代一组用户并将他们的相应
您好,我正在试用 Springs 异步执行器,发现您可以使用 @Async。我想知道是否有可能在 @Async 中使用 @Async,要求是需要将任务委托(delegate)给 @Async 方法在第
我需要支持取消一个函数,该函数返回一个可以在启动后取消的对象。在我的例子中,requester 类位于我无法修改的第 3 方库中。 actor MyActor { ... func d
假设 asyncSendMsg不返回任何内容,我想在另一个异步块中启动它,但不等待它完成,这之间有什么区别: async { //(...async stuff...) for msg
我想用 Mocha 测试异步代码. 我跟着这个教程testing-promises-with-mocha .最后,它说最好的方法是 async/await。 以下是我的代码,我打算将 setTimeo
正如我有限(甚至错误)的理解,Async.StartImmediate 和 Async.RunSynchronously 在当前线程上启动异步计算。那么这两个功能究竟有什么区别呢?谁能帮忙解释一下?
我有一行使用await fetch() 的代码。我正在使用一些调用 eval("await fetch ...etc...") 的脚本注入(inject),但问题是 await 在执行时不会执行从ev
我正在尝试使用 nodeJS 构建一个网络抓取工具,它在网站的 HTML 中搜索图像,缓存图像源 URL,然后搜索最大尺寸的图像。 我遇到的问题是 deliverLargestImage() 在循环遍
我想结合使用 async.each 和 async.series,但得到了意想不到的结果。 async.each([1, 2], function(item, nloop) { async.s
我的代码有问题吗?我使用 async.eachSeries 但我的结果总是抛出 undefined。 这里是我的代码: async.eachSeries([1,2,3], function(data,
我想在 trait 中编写异步函数,但是因为 async fn in traits 还不被支持,我试图找到等效的方法接口(interface)。这是我在 Rust nightly (2019-01-0
async setMyPhotos() { const newPhotos = await Promise.all(newPhotoPromises); someOtherPromise();
async.js 中 async.each 与 async.every 的区别?似乎两者都相同,只是 async.every 返回结果。纠正我,我错了。 最佳答案 每个异步 .each(coll, i
我正在尝试对一组项目运行 async.each。 对于每个项目,我想运行一个 async.waterfall。请参阅下面的代码。 var ids = [1, 2]; async.each(ids,
我的目标是测试 API 调用,将延迟考虑在内。我的灵感来自 this post . 我设计了一个沙箱,其中模拟 API 需要 1000 毫秒来响应和更改全局变量 result 的值。测试检查 500
async.each 是否作为异步数组迭代工作? async.eachSeries 是否作为同步数组迭代工作?(它实际上等待响应) 我问这些是因为两者都有回调,但 async.each 的工作方式类似
我是一名优秀的程序员,十分优秀!