VB.NET通用交叉线程操作的两种不同方法; 哪个更好?

Bri*_*ahy 5 vb.net generics multithreading invoke

VB.NET 2010,.NET 4

你好,

我最近读到了使用SynchronizationContext对象来控制某些代码的执行线程.我一直在使用通用子例程来处理(可能)跨线程调用,例如更新使用的UI控件Invoke.我是一名业余爱好者,很难理解任何特定方法的优缺点.我正在寻找一些有关哪种方法可能更可行以及为什么更有用的见解.

更新:此问题的部分原因在于MSDN页面中Control.InvokeRequired的以下语句.

更好的解决方案是使用 SynchronizationContext返回的 SynchronizationContext而不是控件来进行跨线程编组.

而且,对于为什么,在我看来,大多数关于SO上此类问题的问题的答案的建议都提出了Invoke这种方法,并没有提到这种方法.

方法1:

Public Sub InvokeControl(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of T))
    If Control.InvokeRequired Then
        Control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl), New Object() {Control, Action})
    Else
        Action(Control)
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

方法2:

Public Sub UIAction(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of Control))
    SyncContext.Send(New Threading.SendOrPostCallback(Sub() Action(Control)), Nothing)
End Sub
Run Code Online (Sandbox Code Playgroud)

在我的UI表单的构造函数中定义SyncContextThreading.SynchronizationContext对象在哪里(我将它存储在模块中......不确定这是否是最佳选择):

Public Sub New()
    InitializeComponent()
    SyncContext = WindowsFormsSynchronizationContext.Current
End Sub
Run Code Online (Sandbox Code Playgroud)

然后,如果我想Label1在UI表单上更新控件(例如),我会这样做:

InvokeControl(Label1, Sub(x) x.Text = "hello")
Run Code Online (Sandbox Code Playgroud)

要么

UIAction(Label1, Sub(x) x.Text = "hello")
Run Code Online (Sandbox Code Playgroud)

那么,你们都在想什么呢?是一种首选方式还是取决于具体情况?如果你有时间,可以感谢详细!


布莱恩,提前谢谢

Bri*_*ahy 6

好吧,我一直在做一些阅读,由于我没有得到任何答复,我想我应该开始对我自己的问题进行部分回答,其中包含我迄今为止发现的内容:

我发现了一篇有趣的 codeproject 文章,SynchronizationContext讨论了在线程之间(特别是从工作线程到 UI 线程)编组代码的使用。我发现一些有趣的观察:

  • UI 线程的SynchronizationContext对象是在该线程中创建第一个控件时创建的。在此之前,它没有被定义。
  • UI 线程的SynchronizationContext不是该类的实例SynchronizationContext,而是System.Windows.Forms.WindowsFormsSynchronizationContext从 派生的类的实例SynchronizationContext。正是这个类定义了行为Post/Send允许将代码从一个线程编组到另一个线程。
  • SynchronizationContext传递 UI 线程而不是使用UI 线程的一个好处Invoke是,您不必在逻辑中保留对 UI 表单的引用来调用它。
  • Post方法对于完成指标更新之类的事情似乎很有吸引力,因为它是非阻塞的,但是,正如文章指出的,发布的代码中引发的异常会在 UI 线程中引发。即,发布到 UI 的代码中的错误可能会使 UI 崩溃。 Send没有这个问题。发送时抛出的异常在工作线程中抛出。

更新:这是另一篇富有洞察力的文章。在本文中,Kael Rowan 讨论了一种上下文,其中使用SynchronizationContext可能比控件实例的Invoke/BeginInvoke方法更可取。他认为,在编写可重用库时,仅仅出于调用目的而必须维护对库外部控件的引用是不可取的。他为委托提供了代码,确保创建的任何新线程都将共享 UI 线程的SynchronizationContext.

好吧,看来我不会再在这里收到任何评论了。我在这里写的内容是我的无知使我能够得到的最接近的答案。如果有人还有什么要补充的,我肯定会很感激,但我现在要继续了。:/