- 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/
我有一个 winform 应用程序和一个可观察的设置,如下所示: Form form = new Form(); Label lb = new Label(); form.Controls.Add(l
在 Windows 窗体中实现多项选择选项的最佳方法是什么?我想从列表中强制执行单个选择,从默认值开始。 看起来 ComboBox 是一个不错的选择,但是有没有办法指定一个非空白的默认值? 我可以在代
如何在 WinForm 应用程序中保护我的 ConnectionString? 最佳答案 你不能。尽管您可以在 app.config 文件中加密连接字符串,但应用程序需要能够解密它,因此,始终可以检索
有谁知道像 DotNetBar 那样的 Winforms 面包屑样式导航。 http://www.devcomponents.com/dotnetbar/BreadCrumbHorizontalTre
我正在寻找在 Windows 窗体 C# 中实现多选启用列表框的方法。 有什么建议? 谢谢。 最佳答案 只需添加一个 ListBox控制和设置属性:SelectionMode = SelectionM
我有一个简单的 WinForms 应用程序,用于输入测试用例。自从我将此应用程序升级到 .NET 4.0 并将新的标签页添加到标签页控件以根据 XSD 架构验证 XML 以来,该应用程序一直随机崩溃。
在老式的 MFC 中,DDX 例程内置了表单条目的验证。例如,可以自动检查用户是否在用于数字输入的文本框中输入了字符串。 Winforms中有这样的机制吗?显然,可以为“onChange”等类型的事件
我主要具有 ASP.Net 背景,并具有一些 MVC 知识。我也做了一些 Silverlight 和 MVVM,但是我现在即将转向 Winforms,我对它的经验很少,所以我想知道如何处理 MVP。
简单的问题,虽然办公室里似乎没有人知道,而且我找不到一个好的方法来问谷歌这个问题。在 winforms 中,如果您有一个处理事件的函数(在本例中是在 focusLost 上),那么该函数是否与触发该事
在 Winform 中,我有一个组框,其中有几个文本框控件。如果我删除组框,文本框也会被删除。它们以某种方式与 Groupbox 联系在一起,尽管我没有故意做任何事情来实现这种情况。问题 - 如何删除
我可以在哈希表中设置表单元素: $Hash = @{} $Hash.Main = New-Object System.Windows.Forms.Form $Hash.Main.Left = 0 $H
我是 Windows 开发新手。我开发了一个 WinForm 应用程序,它与串行设备通信并在图表上绘制数据。该应用程序应每天 7/7 24 小时运行。代码执行正确,但执行几个小时后,UI 卡住,操作系
有没有办法记录 Win Forms 应用程序中的所有点击?我想拦截点击并记录该操作以及导致该操作的控件的名称。 这可能吗? 提前致谢。 更新:我正在寻找一个应用程序范围的解决方案,是否没有办法将监听器
我不知道这是否会影响其他控件,但对于列表框和选中列表框,列表框的底部仅以一定的间隔随表单调整大小。 假设我有一个表单和一个列表框,该列表框与表单边缘的所有边都有 2px 间隙,并锚定在所有四个边上。现
我在大多数 WinForms 控件的设计 View 中看到“Tag”属性。我从未使用过此标签,并且想知道为什么我要使用它。 最佳答案 它允许您使用控件存储一些自己的数据。它在树控件中最有用,您可能希望
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
如果有,有人吗?鱼眼 (菜单/ Pane )窗体在 Ajax 应用程序中常见的控件: 例如:http://interface.eyecon.ro/demos/fisheye.html 用 google
这是 Determine Label Size based upon amount of text and font size in Winforms/C# 的倒数. 给定一个高度固定但宽度可变的矩形
我们公司正在研究为我们的开发团队采购 22"显示器。当前唯一的问题是我们的用户将使用较小的屏幕。 我们尝试使用屏幕网格工具(gridmove 和 nvidia 的 utils),但它们并不完全现实。
我有一个 winforms 应用程序,它在网络服务请求期间被锁定 我已经尝试使用 doEvents 来保持应用程序解锁,但它仍然不够响应, 我怎样才能绕过这个锁定,让应用程序始终响应? 最佳答案 最好
我是一名优秀的程序员,十分优秀!