Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.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# &引用;等待任务。配置等待(false)";对;等待ContextSwitcher.SwitchToThreadPool();_C#_.net_.net Core_Async Await_Task Parallel Library - Fatal编程技术网

C# &引用;等待任务。配置等待(false)";对;等待ContextSwitcher.SwitchToThreadPool();

C# &引用;等待任务。配置等待(false)";对;等待ContextSwitcher.SwitchToThreadPool();,c#,.net,.net-core,async-await,task-parallel-library,C#,.net,.net Core,Async Await,Task Parallel Library,广泛建议如下使用ConfigureAwait(false): await Do1Async().ConfigureAwait(false); // ... await Do2Async().ConfigureAwait(false); // ... await Do3Async().ConfigureAwait(false); // ... try { await Do1Async(); // UI thread await ContextSwitcher.SwitchToThread

广泛建议如下使用
ConfigureAwait(false)

await Do1Async().ConfigureAwait(false);
// ...
await Do2Async().ConfigureAwait(false);
// ...
await Do3Async().ConfigureAwait(false);
// ...
try
{
  await Do1Async(); // UI thread
  await ContextSwitcher.SwitchToThreadPool();
  await Do2Async(); // Thread pool thread
}
catch (Exception)
{
  ... // Unknown thread
}
IIRC,同时,人们普遍不鼓励使用这样的东西,它会将异步执行流上下文切换到池线程,从而有助于避免
ConfigureAwait
在我的方法中横行:

await ContextSwitcher.SwitchToThreadPool(); // this was even removed from async CTP

await Do1Async();
// ...
await Do2Async();
// ...
await Do3Async();
// ...
为什么第一个选项被认为是一个好的实践,而这个选项不是,特别是考虑到
等待Do1Async()之后的代码。ConfigureAwait(false)
将在与
等待ContextSwitcher.SwitchToThreadPool()之后的代码完全相同的条件下继续运行

此外,还有另一种选择

await Task.Run(async () => {
   await Do1Async();
   // ...
   await Do2Async();
   // ...
   await Do3Async();
   // ...
});
IIRC,这仍然比
ContextSwitcher
选项好,但是为什么呢?

最后,还有一个有趣的方法:

以下是同步ContextRemover的相关部分:

像这样删除同步上下文安全吗?在等待新的SynchronizationContextRemover()之后,AFAIU会影响整个同步作用域。


这个
SynchronizationContextRemover
ContextSwitcher
好多少,而且它可能少了一个到池线程的开关?

正如其他人所指出的,
配置等待(false)
对于现代代码来说不太必要(特别是,因为ASP.NET内核已经成为主流)。在这一点上,是否在你的图书馆中使用它是一种判断;就个人而言,我仍然使用它,但我的主要异步库是非常低级的

特别是考虑到
await Do1Async().ConfigureAwait(false)
之后的代码将以与
await ContextSwitcher.SwitchToThreadPool()之后的代码完全相同的条件继续运行

条件并不完全相同-如果同步完成
Do1Async
,则情况有所不同

为什么第一个选项被认为是一个好的实践,而这个选项不是

同样,“切换器”方法允许这样的代码:

await Do1Async().ConfigureAwait(false);
// ...
await Do2Async().ConfigureAwait(false);
// ...
await Do3Async().ConfigureAwait(false);
// ...
try
{
  await Do1Async(); // UI thread
  await ContextSwitcher.SwitchToThreadPool();
  await Do2Async(); // Thread pool thread
}
catch (Exception)
{
  ... // Unknown thread
}
具体地说,
catch
finally
块可以在未知的线程上下文中运行,具体取决于运行时行为。可以在多个线程上运行的代码更难维护。这就是它被从异步CTP中删除的主要原因(也要记住,对于当时的语言,您不能在
catch
finally
中等待
,因此无法切换到所需的上下文)

IIRC,这仍然比
ContextSwitcher
选项好,但是为什么呢?

我认为需要注意的是,这些都是不同的语义——特别是,它们都在说完全不同的东西:

  • await x.ConfigureAwait(false)
    表示“我不在乎恢复哪个线程。它可以是同一个线程或线程池线程,无论什么。”注意:它没有说“切换到线程池线程。”
  • wait ContextSwitcher()
    说“切换到此上下文并继续执行”
  • 等待任务。Run(…)
    说“在线程池线程上运行此代码,然后恢复我。”
在所有这些中,我更喜欢第一个和第三个。我使用
ConfigureAwait(false)
表示“此方法不关心它恢复的线程”,我使用
Task.Run
表示“在后台线程上运行此代码”。我不喜欢“切换器”方法,因为我发现它会降低代码的可维护性

像这样删除同步上下文安全吗?在等待新的SynchronizationContextRemover()之后,AFAIU会影响整个同步作用域。

对,;棘手的部分是它需要影响同步作用域。这就是为什么没有
Func
Func
的原因,它们的作用几乎相同。
NoContext
SynchronizationContextRemover
之间的一个主要区别是,地雷强制使用一个范围(lambda),其中没有上下文,而remover是一个“切换器”的形式。同样,我的方法强制代码说“在没有上下文的情况下运行此代码”,而切换器说“在我的方法中的这一点上,删除上下文,然后继续执行”。在我看来,显式作用域的代码更易于维护(再次考虑
catch
/
finally
块),这就是我使用这种API风格的原因

这个
SynchronizationContextRemover
ContextSwitcher
好多少,而且它可能少了一个到池线程的切换


SynchronizationContextRemover
NoContext
都位于同一线程上;它们只是暂时删除该线程上的上下文
ContextSwitcher实际上会切换到线程池线程。

正如其他人所指出的,
ConfigureAwait(false)
对于现代代码来说不太必要(特别是因为ASP.NET核心已经成为主流)。在这一点上,是否在你的图书馆中使用它是一种判断;就个人而言,我仍然使用它,但我的主要异步库是非常低级的

特别是考虑到
await Do1Async().ConfigureAwait(false)
之后的代码将以与
await ContextSwitcher.SwitchToThreadPool()之后的代码完全相同的条件继续运行

条件并不完全相同-如果同步完成
Do1Async
,则情况有所不同

为什么第一个选项被认为是一个好的实践,而这个选项不是

同样,“切换器”方法允许这样的代码:

await Do1Async().ConfigureAwait(false);
// ...
await Do2Async().ConfigureAwait(false);
// ...
await Do3Async().ConfigureAwait(false);
// ...
try
{
  await Do1Async(); // UI thread
  await ContextSwitcher.SwitchToThreadPool();
  await Do2Async(); // Thread pool thread
}
catch (Exception)
{
  ... // Unknown thread
}
具体地说,
catch
finally
块可以在未知的线程上下文中运行,具体取决于运行时行为。可以使用r的代码