标签: synchronizationcontext

Task.Run什么时候使用ExecutionContext流动SynchronizationContext?

本文来自SynchronizationContext可能与ExecutionContext以下情况有关的州:

private void button1_Click(object sender, EventArgs e)  { 
    button1.Text = await Task.Run(async delegate 
    { 
        string data = await DownloadAsync(); 
        return Compute(data); 
    });  
}
Run Code Online (Sandbox Code Playgroud)

这是我的心理模型告诉我将使用此代码发生的事情.用户单击button1,导致UI框架在UI线程上调用button1_Click.然后代码启动一个工作项以在ThreadPool上运行(通过Task.Run).该工作项启动一些下载工作并异步等待它完成.然后,ThreadPool上的后续工作项对该下载的结果执行一些计算密集型操作,并返回结果,从而导致在UI线程上等待的任务完成.此时,UI线程处理此button1_Click方法的其余部分,将计算结果存储到button1的Text属性中.

如果SynchronizationContext不作为ExecutionContext的一部分流动,我的期望是有效的.然而,如果它确实流动,我将非常失望.Task.Run在调用时捕获ExecutionContext,并使用它来运行传递给它的委托.这意味着调用Task.Run时当前的UI SynchronizationContext将流入Task,并在调用DownloadAsync并等待生成的任务时为Current.这意味着await将看到Current SynchronizationContext并将异步方法的剩余部分作为在UI线程上运行的延续.这意味着我的Compute方法很可能会在UI线程上运行,而不是在ThreadPool上运行,从而导致我的应用程序出现响应问题.

故事现在变得有点混乱:ExecutionContext实际上有两个Capture方法,但只有一个是公共的.内部的(mscorlib内部)是mscorlib公开的大多数异步功能所使用的,它可选地允许调用者禁止捕获SynchronizationContext作为ExecutionContext的一部分; 对应于此,还有一个Run方法的内部重载,它支持忽略存储在ExecutionContext中的SynchronizationContext,实际上假装没有捕获一个(这也是mscorlib中大多数功能使用的重载).这意味着几乎任何其核心实现驻留在mscorlib中的异步操作都不会将SynchronizationContext作为ExecutionContext的一部分流,但是其核心实现驻留在任何其他位置的任何异步操作都会将SynchronizationContext作为ExecutionContext的一部分进行流动.我之前提到异步方法的"构建器"是负责在异步方法中流动ExecutionContext的类型,并且这些构建器确实存在于mscorlib中,并且它们确实使用内部重载...因此,SynchronizationContext不作为ExecutionContext的一部分流动等待(再次,这与任务等待者如何支持捕获SynchronizationContext和Post'ing回到它是分开的).为了帮助处理ExecutionContext确实流动SynchronizationContext的情况,异步方法基础结构尝试忽略由于流动而设置为Current的SynchronizationContexts.

然而,它是不完全清楚,我这件事会发生.看来,当公众会发生ExecutionContext.Capture使用方法和内部Task.Run抑制流动过载SynchronizationContextExecutionContext使用,但我不知道什么时候,这将是.

在我的.NET 4.5的测试Task.Run似乎并不流动SynchronizationContextExecutionContext:

private async void button1_Click(object sender, EventArgs e) {
    Console.WriteLine("Click context:" + SynchronizationContext.Current);
    button1.Text = await Task.Run(async delegate {

        // In my tests this always returns …
Run Code Online (Sandbox Code Playgroud)

c# asynchronous synchronizationcontext async-await

2
推荐指数
1
解决办法
1543
查看次数

BackgroundWorker进程需要引发要在主(UI)线程上处理的自定义事件

我有一个大型CSV文件的解析器类.解析方法逐行读取大文件的工作是在backgroundWorker中完成的.使用该backgroundWorker.ReportProgress方法将完整信息的百分比传递给UI线程,以便表单上的进度条可以完成其任务.这工作正常.

但是,我还想提出一个自定义事件,该事件将从CSV文件第一行获取的字段名列表发送回UI(WPF),以便将它们放在下拉列表中.如果解析器遇到格式错误的线路或其他路障,我还想通过事件通知用户.

我的解析器进程在后台执行只能引发一个事件吗?或者必须将SynchronizationContext.Current从主UI线程传递到我的解析器类,然后使用Post方法?

c# wpf backgroundworker synchronizationcontext

1
推荐指数
1
解决办法
4073
查看次数

SynchronizationContext - 奇怪的行为

public static void Init()
{
    //var task = GetSource1();
    //var task = GetSource2();
    //var task = GetSource3();
    var task = MyClient();
    MessageBox.Show(task.Result);
}

private static async Task<string> GetSource1()
{
    var sourceTask = WebClient();
    sourceTask.ConfigureAwait(false);
    return await sourceTask;
}

private static async Task<string> GetSource2()
{
    var sourceTask = MyClient();
    sourceTask.ConfigureAwait(true);
    return await sourceTask;
}

private static async Task<string> GetSource3()
{
    var sourceTask = MyClient();
    sourceTask.ConfigureAwait(false);
    return await sourceTask;
}

private static async Task<string> WebClient()
{
    return await new WebClient().DownloadStringTaskAsync("http://4pda.ru").ConfigureAwait(false);
}

private …
Run Code Online (Sandbox Code Playgroud)

.net c# synchronizationcontext task-parallel-library async-await

1
推荐指数
1
解决办法
43
查看次数

异步调用后跨线程异常

下面的代码块仅对 Npgsql 导致跨线程无效操作异常(不包括 sqlclient、sqlite、mysql、文件读取异步)。

private async void button1_Click(object sender, EventArgs e)
{
   var strBuilder = new Npgsql.NpgsqlConnectionStringBuilder()
   {
        Host = "localhost",
        Username = "postgres",
        Password = "password"
   };
   using (var conn = new Npgsql.NpgsqlConnection(strBuilder.ConnectionString))
   {
      try
      {
          await conn.OpenAsync();
          if (conn.State ==ConnectionState.Open)
          {
             MessageBox.Show("Connected");
             this.button1.Text = "CROSS-THREAD-With-NPGSQL";
          }
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

我查看了 Npgsql 的代码并找到了此链接: https://github.com/npgsql/npgsql/blob/2dd46e7c544caf3302ca7b89dd888a16dccf5c2c/src/Npgsql/PGUtil.cs

文件底部写道:

该机制用于在执行 Npgsql 代码时临时将当前同步上下文设置为 null,从而使所有等待延续在线程池上执行。这取代了在任何地方放置ConfigureAwait(false)的需要,并且应该在所有表面异步方法中使用,无一例外。

我从 Roji(Npgsql 存储库的所有者)那里得到了相当多的解释,但我需要理解为什么我没有看到其他驱动程序的类似问题。npgsql 临时禁用 SynchronizationContext 的方式是否被认为是最佳实践?我正在尝试查看其他驱动程序的源代码,但这需要一段时间,所以我希望我能得到一些帮助,以朝着正确的方向前进。

编辑 1:Stephen Cleary 在下面给出了非常详细的答案,但我也想在这里发布我的一些发现。它可能会帮助其他人。2016 年 9 月 24 日,npgsql 用 NoSynchronizationContextScope 替换了所有的ConfigureAwait(false)。正如 Stephen 所解释的,NoSynchronizationContextScope …

c# database multithreading synchronizationcontext async-await

1
推荐指数
1
解决办法
833
查看次数

是否可以将Task <T>(带有返回值)传递给现有(即已经运行的)线程

在wpf中,我有两个不同线程的窗口.
从窗口A'在线程中AI想要在窗口B'的Tread B中启动一个任务并等待线程A中的返回值.
它假设它可能但是如何?
你知道一个例子吗?

c# wpf task synchronizationcontext async-await

0
推荐指数
1
解决办法
84
查看次数