Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何禁止ExecutionContext捕获当前SynchronizationContext?_C#_.net_Async Await_Synchronizationcontext - Fatal编程技术网

C# 如何禁止ExecutionContext捕获当前SynchronizationContext?

C# 如何禁止ExecutionContext捕获当前SynchronizationContext?,c#,.net,async-await,synchronizationcontext,C#,.net,Async Await,Synchronizationcontext,我的问题是由以下一个例子提出的: 下面是我的心智模型告诉我的,这个代码会发生什么。A. 用户单击按钮1,导致UI框架调用按钮1\u单击 在UI线程上。然后,代码启动一个工作项以在 线程池(通过Task.Run)。该工作项开始一些下载工作 并异步等待它完成。后续工作项 然后在线程池上对 下载的结果,并返回结果,导致 正在等待UI线程完成。此时,用户界面 线程处理此按钮单击方法的其余部分,存储 将计算结果输入button1的文本属性 如果SynchronizationContext不作为一部分流动,

我的问题是由以下一个例子提出的:

下面是我的心智模型告诉我的,这个代码会发生什么。A. 用户单击按钮1,导致UI框架调用按钮1\u单击 在UI线程上。然后,代码启动一个工作项以在 线程池(通过Task.Run)。该工作项开始一些下载工作 并异步等待它完成。后续工作项 然后在线程池上对 下载的结果,并返回结果,导致 正在等待UI线程完成。此时,用户界面 线程处理此按钮单击方法的其余部分,存储 将计算结果输入button1的文本属性

如果SynchronizationContext不作为一部分流动,我的期望是有效的 执行上下文。但是,如果它真的流了,我会非常难过 失望。Task.Run在调用时捕获ExecutionContext,并且 使用它运行传递给它的委托。这意味着用户界面 调用Task.Run时当前的SynchronizationContext 将流入任务,并且在调用时是当前的 下载Async并等待生成的任务。那就意味着 等待将看到当前SynchronizationContext并发布 异步方法的剩余部分作为在 用户界面线程。这意味着我的计算方法很可能是 在UI线程上运行,而不是在线程池上运行,导致 我的应用程序的响应问题

让我们用以下例子来代替本文中的例子:

private void button1_Click(object sender, EventArgs e)  { 
    button1.Text = await DownloadAndComputeAsync(); 
}

// Can't be changed
private async Task<string> DownloadAndComputeAsync() {
    return await Task.Run(async delegate 
    { 
        string data = await DownloadAsync(); 
        return Compute(data); 
    });  
}
用例 我不知道我会想要/需要使用它,但在阅读了我在顶部链接的文章后,我可以想到一些可能有用的地方

  • 如果从UI上下文中,我使用的库不使用
    ConfigureAwait(false)
    ,并且最终在UI线程上完成了大量工作。诚然,如果可能的话,我可能会停止使用图书馆

  • 目前推荐的最佳做法似乎是以下之一

  • 在任何地方使用
    ConfigureAwait(false)
    ,除非您知道需要返回到当前上下文。这样做的缺点是
    ConfigureAwait(false)
    非常难看,并且会对代码可读性产生负面影响(imo)
  • 仅在库代码中使用
    ConfigureAwait(false)
    ,但在所有内部代码中注意是否可以从UI上下文等使用给定的异步方法,并仅在绝对需要时使用
    ConfigureAwait(false)
    。这似乎不太理想,因为这意味着类必须知道它们的异步方法是否可能被调用,例如UI上下文
  • 我想知道是否有第三种可能性:在任何时候调用异步方法时都需要在内部代码中,例如。,事件处理程序或类似程序中的代码负责确保异步方法不会将UI上下文作为其当前上下文,因此不需要使用
    ConfigureAwait(false)
    在UI上下文中调用它。这样做的好处是,所有内部非UI代码不需要使用
    ConfigureAwait(false)
    ,即使它是从事件处理程序调用的,并且所有上下文感知代码仅限于事件处理程序中的UI代码


    首先;这里不要使用异步委托。您不必要地使代码复杂化了

    当您有一个已经异步的操作想要得到结果时,
    等待它。如果您必须执行CPU受限的工作,则在
    任务中运行该工作。运行
    调用并
    等待
    以获得结果

    private void button1_Click(object sender, EventArgs e)  
    { 
        string data = await DownloadAsync(); 
        button1.Text = await Task.Run(() => Compute(data));
    }
    
    这里很清楚发生了什么。获取异步操作的结果,使用它在非UI线程中执行一些CPU绑定的工作,然后在UI上下文中使用该结果


    现在,说到这里,我希望您的代码实际上能够正常工作(假设当前上下文在整个
    任务中都不是UI上下文。请运行
    委托),但要理解代码或查看它在做什么要困难得多。

    首先;这里不要使用异步委托。您不必要地使代码复杂化了

    当您有一个已经异步的操作想要得到结果时,
    等待它。如果您必须执行CPU受限的工作,则在
    任务中运行该工作。运行
    调用并
    等待
    以获得结果

    private void button1_Click(object sender, EventArgs e)  
    { 
        string data = await DownloadAsync(); 
        button1.Text = await Task.Run(() => Compute(data));
    }
    
    这里很清楚发生了什么。获取异步操作的结果,使用它在非UI线程中执行一些CPU绑定的工作,然后在UI上下文中使用该结果


    现在,说到这里,我希望您的代码实际上能够正常工作(假设当前上下文在整个
    任务中都不是UI上下文。请运行
    委托),但要理解代码或查看它在做什么要困难得多。

    首先;这里不要使用异步委托。您不必要地使代码复杂化了

    当您有一个已经异步的操作想要得到结果时,
    等待它。如果您必须执行CPU受限的工作,则在
    任务中运行该工作。运行
    调用并
    等待
    以获得结果

    private void button1_Click(object sender, EventArgs e)  
    { 
        string data = await DownloadAsync(); 
        button1.Text = await Task.Run(() => Compute(data));
    }
    
    这里很清楚发生了什么。获取异步操作的结果,使用它在非UI线程中执行一些CPU绑定的工作,然后在UI上下文中使用该结果

    现在,说到这里,我希望您的代码实际上能够正常工作(假设当前上下文在整个
    任务中都不是UI上下文。运行
    委托),但是理解代码或查看它是什么要困难得多