标签:reac private rms null 涵盖 forms 无法 oid cell
无论是什么平台(ASP.NET 、WinForm 、WPF 等),所有 .NET 程序都包含 同步上下文 概念,并且所有多线程编程人员都可以通过理解和应用它获益。
原始多线程
ISynchronizeInvoke 的诞生
.NET Framework
首次发布时,这一通用模式是标准化模式。ISynchronizeInvoke
诞生了。ISynchronizeInvoke 的原理
ISynchronizeInvoke
还提供了一个属性来确定当前代码是否已在目标线程上运行。ISynchronizeInvoke
实现,并且开发了一种模式来设计异步组件。ISynchronizeInvoke
不太适合 ASP.NET 异步页面体系结构。
ISynchronizeInvoke
模式开发的异步组件在 ASP.NET 页面内无法正常工作,因为 ASP.NET 异步页面不与单个线程关联。SynchronizationContext
取代了 ISynchronizeInvoke
。ISynchronizeInvoke
满足了两点需求:
设计 SynchronizationContext
是为了替代 ISynchronizeInvoke
,但完成设计后,它就不仅仅是一个替代品了。
SynchronizationContext
提供了一种方式,可以使工作单元列队并列入上下文。
SynchronizationContext
实现都不是基于单个特定线程的。SynchronizationContext
不包含用来确定是否必须同步的机制,因为这是不可能的。
Dispatcher.Invoke
是将委托列入上下文,不等委托执行直接返回txtUName.Invoke
会启动一个process,等到委托执行完毕后返回void OperationCompleted()
。// SynchronizationContext API的重要方面
class SynchronizationContext
{
// 将工作分配到上下文中
void Post(..); // (asynchronously 异步)
void Send(..); // (synchronously 同步)
// 跟踪异步操作的数量。
void OperationStarted();
void OperationCompleted();
// 每个线程都有一个Current Context。
// 如果“Current”为null,则按照惯例,
// 最开始的当前上下文为 new SynchronizationContext()。
static SynchronizationContext Current { get; }
//设置当前同步上下文
static void SetSynchronizationContext(SynchronizationContext);
}
不同的框架和主机可以自行定义上下文
通过了解这些不同的实现及其限制,可以清楚了解 SynchronizationContext
概念可以和不可以实现的功能
位于:System.Windows.Forms.dll:System.Windows.Forms
WinForm
WindowsFormsSynchronizationContext
UI Control
的每个线程的当前上下文SynchronizationContext
使用 UI Control
的 Invoke
等方法(ISynchronizeInvoke
派生出来的),该方法将委托传递给基础 Win32
消息循环WindowsFormsSynchronizationContext
的上下文是一个单例的 UI 线程WindowsFormsSynchronizationContext
列队的所有委托一次一个地执行
位于:WindowsBase.dll:System.Windows.Threading
WPF
Dispatcher
中列队Dispatcher.Run
开启 循环调度器 时,将这个初始化完成的 同步上下文 安装到当前上下文DispatcherSynchronizationContext
的上下文是一个单独的 UI 线程。DispatcherSynchronizationContext
的所有委托均由特定的UI线程一次一个按其排队的顺序执行DispatcherSynchronizationContext
,即使它们都使用相同的基础调度程序也是如此。调度线程池线程的同步上下文。
位于:mscorlib.dll:System.Threading
Default SynchronizationContext
是默认构造的 SynchronizationContext
对象。
Default SynchronizationContext
。Default SynchronizationContext
将其异步委托列队到 ThreadPool
,但在调用线程上直接执行其同步委托。Default SynchronizationContext
涵盖所有 ThreadPool
线程以及任何调用 Send
的线程。Send
的线程们,将这些线程放入这个上下文,直至委托执行完成
Default SynchronizationContext
应用于 线程池 线程,除非代码由 ASP.NET 承载。Default SynchronizationContext
还隐式应用于显式子线程(Thread 类的实例),除非子线程设置自己的 SynchronizationContext
。因此,UI 应用程序通常有两个同步上下文:
UI SynchronizationContext
Default SynchronizationContext
BackgroundWorker
运行流程
BackgroundWorker
捕获并使用调用 RunWorkerAsync
的线程的 同步上下文Default SynchronizationContext
中执行DoWork
RunWorkerCompleted
事件UI同步上下文 中只有一个 BackgroundWorker
,因此 RunWorkerCompleted
在 RunWorkerAsync
捕获的 UI同步上下文中执行(如下图)。
UI同步上下文中的嵌套 BackgroundWorker
BackgroundWorker
从其 DoWork
处理程序启动另一个 BackgroundWorker
BackgroundWorker
不会捕获 UI同步上下文DoWork
由 线程池 线程使用 默认同步上下文 执行。
RunWorkerAsync
将捕获默认 SynchronizationContext
RunWorkerCompleted
默认情况下,控制台应用程序 和 Windows服务 中的所有线程都只有 Default SynchronizationContext
,这会导致一些基于事件的异步组件失败(也就是没有UI同步上下文的特性)
Nito.Async
库的 ActionThread
类可用作通用同步上下文实现。位于:System.Web.dll:System.Web [internal class]
ASP.NET
SynchronizationContext
在线程池线程执行页面代码时安装完成。AspNetSynchronizationContext
中时,它设置原始页面的 identity 和 culture 到此线程,然后直接执行委托
Post
“异步”列入的,也会直接调用委托。从概念上讲, AspNetSynchronizationContext
的上下文非常复杂。
AspNetSynchronizationContext
确保一次只执行其中一项。它们可以在任意线程上执行,但该线程将具有原始页面的 identity 和 culture。一个常见的示例:
在异步网页中使用 WebClient.DownloadDataAsync 将捕获当前 SynchronizationContext
,之后在该上下文中执行其 DownloadDataCompleted
事件。
DownloadDataAsync
,然后返回;
WebClient
对象下载所请求的数据后,它将在线程池线程上收到通知
DownloadDataCompleted
SynchronizationContext
提供了一种途径,可以在很多不同框架中编写组件
BackgroundWorker
和 WebClient
就是两个在 WinForm
、WPF
、Console
和 ASP.NET Application
中同样应用自如的组件。在设计这类可重用组件时,必须注意几点:
ISynchronizeInvoke.InvokeRequired
的等效项
Concrol
对象进行方法调用时,调用方是否必须通过 Invoke
进行调用(传入委托)。Control
)对象被绑定到特定线程,并且不是线程安全的。Invoke
方法将对相应线程调用的委托列队WindowsFormsSynchronizationContext
确实 1:1 映射到一个线程(只要不调用 SynchronizationContext.CreateCopy
)
SynchronizationContext.Post
方法不一定是异步的
AspNetSynchronizationContext
是一个明显的例外同步上下文实现类的摘要
使用特定线程 执行委托 | 独占 (一次执行一个委托) | 有序 (委托按队列顺序执行) | Send 可以直接调用委托 | Post 可以直接调用委托 | ||
---|---|---|---|---|---|---|
Winform | 能 | 能 | 能 | 如果从UI线程调用 | 从不 | |
WPF/Silverlight | 能 | 能 | 能 | 如果从UI线程调用 | 从不 | |
Default | 不能 | 不能 | 不能 | Always | 从不 | |
ASP.NET | 不能 | 能 | 不能 | Always | Always |
AsyncOperationManager
和 AsyncOperation
类是 SynchronizationContext
抽象类的轻型包装
AsyncOperation
的异步是使用抽象的同步上下文进行封装的AsyncOperationManager
在第一次创建 AsyncOperation
时捕获当前同步上下文 ,如果当前同步上下文为null
,则使用 Default
同步上下文AsyncOperation
将委托异步发布到捕获的 同步上下文AsyncOperationManager
和 AsyncOperation
新组件不应使用基于事件的异步模式
Task
的 API 是 .NET 中异步编程的发展方向BackgroundWorker
和 WebClient
这样的简单组件是隐式自带的
SynchronizationContext
公开 API,Libraries 不仅获得了框架独立性,而且为高级最终用户提供了一个可扩展点。ExecutionContext
WCF 有两个用于配置服务器和客户端行为的特性:
ServiceBehaviorAttribute
和 CallbackBehaviorAttribute
UseSynchronizationContext
设置为 false
可以禁止 WCF 自动使用 同步上下文
WorkflowInstance
类及其派生的 WorkflowApplication
类的SynchronizationContext
属性
如果承载进程创建自己拥有的 WorkflowInstance
,同步上下文也许直接设置了
WorkflowInvoker.InvokeAsync
也使用 同步上下文
internal
的 WorkflowApplication
Post
工作流完成事件以及工作流活动TaskScheduler.FromCurrentSynchronizationContext
TPL 使用 Task
对象作为其工作单元并通过 TaskScheduler
执行。
TaskScheduler
的作用类似于 Defalut 同步上下文 ,将 Task
在 ThreadPool
中列队。TaskScheduler
,将 Task
在 一个同步上下文 中列队
Task
中完成,如下所示。UI 进度条更新
private void button1_Click(object sender, EventArgs e)
{
// 捕获当前 SynchronizationContext 的 TaskScheduler.
TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
// Start a new task (this uses the default TaskScheduler,
// so it will run on a ThreadPool thread).
Task.Factory.StartNew(() =>
{
// We are running on a ThreadPool thread here.
// Do some work.
// Report progress to the UI.
Task reportProgressTask = Task.Factory.StartNew(() =>
{
// We are running on the UI thread here.
// Update the UI with our progress.
},CancellationToken.None,
TaskCreationOptions.None,
taskScheduler);
reportProgressTask.Wait();
// Do more work.
});
}
CancellationToken.Register
CancellationToken
类可用于任意类型的取消操作CancellationToken
将该委托列入 同步上下文 队列,然后才会进行执行ObserveOn
、 SubscribeOn
和 SynchronizationContextScheduler
Rx 是一个库,它将事件视为数据流
ObserveOn(context)
运算符通过一个 同步上下文 将事件列队SubscribeOn(context)
运算符通过一个 同步上下文 将对这些事件的订阅 列队ObserveOn(context)
通常用于使用传入事件更新 UI,SubscribeOn 用于从 UI 对象使用事件Rx 还有它自己的工作单元列队方法: IScheduler
接口。
SynchronizationContextScheduler
SynchronizationContextScheduler(SynchronizationContext context)
await
、 ConfigureAwait
、 SwitchTo
和 EventProgress<T>
await
关键字处被捕获await
关键字后时恢复
await
关键字后面的执行代码会被列入到 该同步上下文 中执行
null
时,才捕获当前 同步上下文null
,则捕获当前 TaskScheduler
private async void button1_Click(object sender, EventArgs e)
{
// 当前 SynchronizationContext 被 await 在暗中捕获
var data = await webClient.DownloadStringTaskAsync(uri);
// 此时,已捕获的SynchronizationContext用于恢复执行,
// 因此我们可以自由更新UI对象。
}
ConfigureAwait
提供了一种途径避免 SynchronizationContext
捕获;
continueOnCapturedContext
参数传递 false
会阻止 await
后的代码,在 await
执行前的 同步上下文 上执行SwitchTo
async
的方法 可以通过调用 SwitchTo
改变到一个不同的同步上下文上,并 awaiting 结果报告异步操作进展的通用模式:
IProgress<T>
接口及其实现 Progress<T>
ProgressChanged
事件返回 void
的 async
方法
这一行为使返回 void
的 async
方法 类似于顶级异步操作。
SynchronizationContext(同步上下文)综述
标签:reac private rms null 涵盖 forms 无法 oid cell
原文地址:https://www.cnblogs.com/BigBrotherStone/p/12240731.html