问题标签 [synchronizationcontext]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c# - 如何抑制 ExecutionContext 捕获当前的 SynchronizationContext?
我的问题是由本文中的一个例子提出的:
这是我的心理模型告诉我的,这段代码会发生什么。用户单击 button1,导致 UI 框架在 UI 线程上调用 button1_Click。然后代码启动一个工作项以在 ThreadPool 上运行(通过 Task.Run)。该工作项开始一些下载工作并异步等待它完成。ThreadPool 上的后续工作项然后对该下载结果执行一些计算密集型操作,并返回结果,从而导致 UI 线程上正在等待的任务完成。此时,UI 线程处理此 button1_Click 方法的剩余部分,将计算结果存储到 button1 的 Text 属性中。
如果 SynchronizationContext 不作为 ExecutionContext 的一部分流动,我的期望是有效的。但是,如果它确实流动,我将非常失望。Task.Run 在调用时捕获 ExecutionContext,并使用它来运行传递给它的委托。这意味着在调用 Task.Run 时处于当前状态的 UI SynchronizationContext 将流入任务,并且在调用 DownloadAsync 并等待生成的任务时处于当前状态。这意味着 await 将看到 Current SynchronizationContext 和 Post 异步方法的其余部分作为继续在 UI 线程上运行。这意味着我的 Compute 方法很可能会在 UI 线程上运行,而不是在 ThreadPool 上运行,从而导致我的应用出现响应问题。
假设我有文章中的示例,而不是:
出于某种原因,我无法将代码更改DownloadAndComputeAsync
为 use ConfigureAwait(false)
,可能是因为它位于库中或我无法控制的其他代码中。
有没有办法可以禁止将 UI 的 SynchronizationContext 捕获作为 ExecutionContext 的一部分?
我在上面链接的文章提到了 Task.Run 的内部版本,它禁止捕获 SynchronizationContext,但它是内部版本。如果它不是内部的,你可以这样做:
用例
我没有一个案例我知道我会想要/需要使用它,但是在阅读了我在顶部链接的文章之后,我可以想到几个可能有用的地方。
如果从 UI 上下文中我使用的库不使用
ConfigureAwait(false)
并最终在 UI 线程上做大量工作。诚然,如果可以的话,在这种情况下,我可能会停止使用该库。当前推荐的最佳实践似乎是以下之一
- 在任何地方使用
ConfigureAwait(false)
,除非您知道您需要回到当前上下文。这样做的缺点ConfigureAwait(false)
是非常丑陋并且对代码可读性产生负面影响(imo)。 - 仅在库代码中使用
ConfigureAwait(false)
,但在所有内部代码中注意是否可以从例如 UI 上下文中使用给定的异步方法,并且ConfigureAwait(false)
仅在绝对需要时使用。这似乎不太理想,因为它意味着类必须知道它们的异步方法是否可能被调用,例如,UI 上下文。
我想知道是否可能存在第三种可能性:在任何时候调用异步方法时都要求在内部代码中,例如,事件处理程序中的代码或类似的代码负责确保异步方法不会执行的 UI 上下文t 将 UI 上下文作为其当前上下文,因此如果
ConfigureAwait(false)
在 UI 上下文上调用它,则不需要使用它。这样做的好处是,所有内部非 UI 代码都不需要使用ConfigureAwait(false)
,即使它是从事件处理程序调用的,并且所有上下文感知代码都仅限于 UI 代码,例如事件处理程序。- 在任何地方使用
c# - Task.Run 何时使用 ExecutionContext 流动 SynchronizationContext?
本文来自SynchronizationContext
可能与以下内容有关的州ExecutionContext
:
这是我的心理模型告诉我的,这段代码会发生什么。用户单击 button1,导致 UI 框架在 UI 线程上调用 button1_Click。然后代码启动一个工作项以在 ThreadPool 上运行(通过 Task.Run)。该工作项开始一些下载工作并异步等待它完成。ThreadPool 上的后续工作项然后对该下载结果执行一些计算密集型操作,并返回结果,从而导致 UI 线程上正在等待的任务完成。此时,UI 线程处理此 button1_Click 方法的剩余部分,将计算结果存储到 button1 的 Text 属性中。
如果 SynchronizationContext 不作为 ExecutionContext 的一部分流动,我的期望是有效的。但是,如果它确实流动,我将非常失望。Task.Run 在调用时捕获 ExecutionContext,并使用它来运行传递给它的委托。这意味着在调用 Task.Run 时处于当前状态的 UI SynchronizationContext 将流入任务,并且在调用 DownloadAsync 并等待生成的任务时处于当前状态。这意味着 await 将看到 Current SynchronizationContext 和 Post 异步方法的其余部分作为在 UI 线程上运行的延续。这意味着我的 Compute 方法很可能会在 UI 线程上运行,而不是在 ThreadPool 上运行,从而导致我的应用出现响应问题。
故事现在变得有点混乱:ExecutionContext 实际上有两个 Capture 方法,但其中只有一个是公共的。内部的(mscorlib 内部的)是从 mscorlib 公开的大多数异步功能所使用的,它可以选择允许调用者禁止捕获 SynchronizationContext 作为 ExecutionContext 的一部分;与此相对应,还有一个 Run 方法的内部重载,它支持忽略存储在 ExecutionContext 中的 SynchronizationContext,实际上假装没有被捕获(这也是 mscorlib 中大多数功能使用的重载)。这意味着几乎任何其核心实现驻留在 mscorlib 中的异步操作都不会将 SynchronizationContext 作为 ExecutionContext 的一部分流动,但是任何其核心实现驻留在其他任何地方的异步操作都会将 SynchronizationContext 作为 ExecutionContext 的一部分流动。我之前提到,异步方法的“构建器”是负责在异步方法中流动 ExecutionContext 的类型,这些构建器确实存在于 mscorlib 中,并且它们确实使用内部重载……因此,SynchronizationContext 不会作为 ExecutionContext 的一部分跨等待(这与任务等待者如何支持捕获 SynchronizationContext 并回传给它是分开的)。为了帮助处理 ExecutionContext 确实流动 SynchronizationContext 的情况,异步方法基础结构尝试忽略由于正在流动而设置为 Current 的 SynchronizationContexts。
但是,我不清楚何时会发生这种情况。似乎在使用公共ExecutionContext.Capture
方法并且不使用抑制流动的内部重载时Task.Run
会SynchronizationContext
发生这种情况,但我不知道那会是什么时候。ExecutionContext
在我对 .NET 4.5 的测试中,Task.Run
似乎并没有SynchronizationContext
使用ExecutionContext
:
所以我的问题是在什么情况下会Compute()
在文章中讨论的 UI 上下文(阻塞 UI 线程)上运行?
c# - 是否可以通过任务(带返回值)到现有的(即已经运行的)线程
在 wpf 中,我在不同的线程中有两个窗口。
从线程 AI 中的窗口 A' 想在窗口 B' 的线程 B 中启动一个任务并等待线程 A 中的返回值。
它认为这是可能的,但如何?
你知道一个例子吗?
asp.net - ASP.Net vs MVC vs WebAPI 和 UseTaskFriendlySynchronizationContext
我有几个 ASP.Net MVC 和 WebAPI 项目。它们中的大多数都是最新的(MVC 5 / WebAPI 2)。自从我实现一个全局过滤器(用于 MVC)和一个委托处理程序(用于 WebAPI)来统一整个系统的安全性以来,我一直在仔细检查我的安全假设。
在这种情况下,我遇到了一些文章和帖子(见下文),它们说您应该始终设置UseTaskFriendlySynchronizationContext
为true
(默认为false
)。这对我来说似乎很奇怪,因为即使在使用 MVC 5 和 WebAPI 2 新项目模板(以及 ASP.Net WebForms 模板)的 VS2013 中也根本没有设置此应用程序设置。
有关此设置的 MSDN 文档实际上不存在,而且我发现确实说异步编程需要它的帖子似乎是在 WebForms 的上下文中。
所以这是我的问题:
- 此设置是否适用于所有 ASP.Net 或者它是否特定于 ASP.Net 中的页面生命周期内容(我没有使用太多)
- 如果它对现代异步编程如此重要,为什么没有任何教程或模板引用它?
- 在使用 ConfigureAwait(false) 的引用库中使用 Thread.CurrentPrincipal 的声明会造成任何问题,还是 ExecutionContext 的逻辑调用上下文的流动会在那里照顾我?(到目前为止我的阅读和测试表明它会)
以下是我看过的一些文章UseTaskFriendlySynchronizationContext
:
- 异步设置 Thread.CurrentPrincipal?
- MSDN 上的 ASP.NET appSettings 元素
- “UseTaskFriendlySynchronizationContext”是什么意思?
SynchronizationContext
Marcus van Houdt了解ASP.NET 中的内容- 为什么 Thread.CurrentPrincipal 需要“等待 Task.Yield()”才能正确流动?
一些真正帮助我了解所有这些东西是如何工作的文章从未提及UseTaskFriendlySynchronizationContext
:
async-await - 安全性、Thread.CurrentPrincipal 和 ConfigureAwait(false)
在使用 ConfigureAwait(false) 的引用库中使用 Thread.CurrentPrincipal 的声明会造成任何问题,还是 ExecutionContext 的逻辑调用上下文的流动会在那里照顾我?(到目前为止,我的阅读和测试表明它会)。
示例 WebAPI 控制器操作:
来自外部引用库的示例加载函数:
此外,答案不能是“那么不要使用 ConfigureAwait(false)!”。这可能会导致其他问题,例如死锁(不要阻塞异步代码)。
c# - .NET 4.0 中 SynchronizationContext.Current 为空的问题的解决方法
SynchronizationContext.Current
.NET 4.0 的主线程上意外为 null的问题的解决方法是什么?看:
c# - 使用 async/await 时使用自定义 SynchronizationContext 序列化执行
我的团队正在 C# 5.0 中使用 async/await 开发一个多线程应用程序。在实现线程同步的过程中,经过多次迭代,我们提出了一个(可能是新颖的?)带有内部锁的新 SynchronizationContext 实现:
- 调用 Post 时:
- 如果可以获取锁,则立即执行委托
- 如果无法获取锁,则委托排队
- 调用发送时:
- 如果可以获取锁,则执行委托
- 如果无法获取锁,则线程被阻塞
在所有情况下,在执行委托之前,上下文将自己设置为当前上下文,并在委托返回时恢复原始上下文。
这是一个不寻常的模式,因为我们显然不是第一个编写这样一个应用程序的人,我想知道:
- 模式真的安全吗?
- 有没有更好的方法来实现线程同步?
这是 SerializingSynchronizationContext 的源代码和GitHub 上的演示。
以下是它的使用方法:
- 每个需要保护的类都创建自己的上下文实例,如互斥锁。
上下文是可等待的,因此可以使用以下语句。
await myContext;
这只会导致方法的其余部分在上下文的保护下运行。
- 类的所有方法和属性都使用这种模式来保护数据。在等待之间,一次只能在上下文上运行一个线程,因此状态将保持一致。当到达等待时,允许下一个调度线程在上下文上运行。
- 如果需要即使使用等待的表达式也可以保持原子性,自定义 SynchronizationContext 可以与 AsyncLock 结合使用。
- 类的同步方法也可以使用自定义上下文进行保护。
c# - 设置 ConfigureAwait 和 SynchronisationContext 的行为
在他的回答中, 斯蒂芬解释说,当ConfigureAwait(false)
被调用时,该方法的其余部分将在线程池线程上执行,除非Task
你await
已经完成了。
什么是明确的:如果我使用ConfigureAwait(false)
在异步调用之后执行的所有内容将在线程池线程上执行,因此不在 UI SynchronizationContext 中运行,否则(尤其是基于 UI 的东西需要textBox1.Text = data.Property
)它在 UI SynchronizationContext 中运行。
我不明白的是:这await
并不意味着Task
我正在等待的总是在方法进行之前完成?那么Task怎么能不完成才继续呢?
c# - C# Application.DoEvents 不能在我的应用程序中工作
由于我的英语不好,我简单地解释我的问题并在此处粘贴代码片段来描述问题。
问题是我们的 winForm 应用程序中的多线程问题。我将逻辑简化为以下代码示例。
在测试代码中,mainForm中有1个mainForm Form1和一个名为“开始”的按钮。当用户单击该按钮时,将从 2 个后台线程显示两个表单 form2 和 form3。form2 关闭后,Form1 将被触发关闭。但是这里显示了form3,所以我需要用户自己关闭form3。所以我处理了 form.Closing 事件并使用 Application.DoEvents() 让用户关闭 form3。它看起来很有效。但实际上,form3 可以接受用户的操作,但 form3 不会按预期关闭。
请说明为什么form3不能在这里关闭以及如何修改代码使用户的关闭操作起作用。
c# - 在另一个线程上捕获异常?
在开发 winform 应用程序时,通常只需调用主 GUI 线程即可完成 GUI 工作。
Invoke
今天已经过时了(如果我没看错的话),你应该SynchronizationContext
改用。
问题是:如何处理异常?我注意到有时在“同步/调用”线程上抛出的异常会丢失?
我确实使用了Application.ThreadException
andAppDomain.CurrentDomain.UnhandledException
但这没有帮助吗?