C# 正在搜索任务。屈服于线程池的等价物

C# 正在搜索任务。屈服于线程池的等价物,c#,async-await,task-parallel-library,C#,Async Await,Task Parallel Library,该方法“创建一个等待的任务,在等待时异步返回到当前上下文。”我正在搜索类似的内容,以确保后面的任何代码都将在线程池线程上运行。我知道我可以通过在任务中包含以下所有代码来实现这一点。运行,但我正在搜索一个不创建内部作用域的内联解决方案 private async void Button1_Click(object sender, EventArgs e) { await Task.Yield(); // Doesn't do what I want // Code that sho

该方法“创建一个等待的任务,在等待时异步返回到当前上下文。”我正在搜索类似的内容,以确保后面的任何代码都将在
线程池
线程上运行。我知道我可以通过在
任务中包含以下所有代码来实现这一点。运行
,但我正在搜索一个不创建内部作用域的内联解决方案

private async void Button1_Click(object sender, EventArgs e)
{
    await Task.Yield(); // Doesn't do what I want
    // Code that should run on the ThreadPool
}

private async void Button1_Click(object sender, EventArgs e)
{
    // Does what I want, but I am not happy with the added indentation and scope
    await Task.Run(() => 
    {
        // Code that should run on the ThreadPool
    });
}
我能想到的最好方法是使用
任务。使用空委托运行
,并将等待配置为捕获同步上下文:

private async void Button1_Click(object sender, EventArgs e)
{
    // Probably does what I want, but it looks ugly
    await Task.Run(() => { }).ConfigureAwait(continueOnCapturedContext: false);
    // Code that should run on the ThreadPool
}
这看起来像是一行晦涩难懂的代码,我不确定这是否充分表达了在那里的意图。我也不确定它是否提供了我想要的保证。还有其他解决办法吗

顺便说一句,这个问题的灵感来自马克·格雷威尔的一篇相关文章


更新:我应该给出一个更具体的原因,说明为什么使用标准的
等待任务。Run(()=>
在我的情况下并不理想。我有一些代码应该在
线程池上运行,或者不运行,这取决于某些条件。因此
任务.Yield
等价物允许我这样做:

private bool _executeOnThreadPool;

private async void Button1_Click(object sender, EventArgs e)
{
    if (_executeOnThreadPool) await SwitchToTheThreadPool();
    // Code that should run on the ThreadPool or the UI thread
}

我不能用
任务做同样的事情。运行
时不需要代码复制,也不需要添加lambdas和间接寻址。

陈雷蒙在他的博客中发布了这一点

在这里复制,以防源丢失:

使用制度; 使用System.Runtime.CompilerServices; 使用System.Threading;//用于线程池 使用System.Windows.Forms;//用于Windows窗体 使用System.Windows.Threading;//用于WPF //用于WPF 结构DispatcherThreadSwitcher:INotifyCompletion { 内部DispatcherThreadSwitcher(Dispatcher Dispatcher)=> this.dispatcher=dispatcher; public DispatcherThreadSwitcher GetAwaiter()=>this; public bool IsCompleted=>dispatcher.CheckAccess(); public void GetResult(){} 未完成的公共作废(行动继续)=> 调度员开始通话(续); 调度员; } //适用于Windows窗体 结构控制线程切换器:INotifyCompletion { 内部控制线程切换器(控制)=> 这个控制=控制; 公共控制线程切换器GetAwaiter()=>this; public bool IsCompleted=>!control.invokererequired; public void GetResult(){} 未完成的公共作废(行动继续)=> 控制。开始激活(续); 控制; } //适用于WPF和Windows窗体 结构ThreadPoolThreadSwitcher:INotifyCompletion { public ThreadPoolThreadSwitcher GetAwaiter()=>this; 公共布尔已完成=> SynchronizationContext.Current==null; public void GetResult(){} 未完成的公共作废(行动继续)=> QueueUserWorkItem(=>continuation()); } 类线程切换器 { //用于WPF 静态公共DispatcherThreadSwitcher ResumeForegroundAsync( 调度员)=> 新调度员线程切换器(调度员); //适用于Windows窗体 静态公共控制线程切换器ResumeForegroundAsync( 控制)=> 新型控制螺纹切换器(控制); //适用于WPF和Windows窗体 静态公共ThreadPoolThreadSwitcher ResumeBackgroundAsync()=> 新的ThreadPoolThreadSwitcher(); } 这使您可以执行以下操作:

await ThreadSwitcher.ResumeBackgroundAsync(); 等待ThreadSwitcher.ResumeBackgroundAsync();

然而,我会对在共享代码库中实际执行此操作持谨慎态度:它不是特别惯用的,而
Task.Run
非常清晰。

wait Task.Delay(0)。configurewait(false);
?另外,我要说第二个选项是最清晰的。@GuruStron AFAIK the
Task.Delay(0)
返回一个已完成的任务,因此以下代码将在UI线程上继续。是的。似乎是这样。然后task.Delay(1)=)@GuruStron我也不太满意,因为它引入了一个微小但不必要的人为延迟。您可以格式化代码并避免缩进>:Thaks canton7,这非常有用!通过对
ThreadPoolThreadSwitcher
s属性
IsCompleted
,我成功地实现了我想要的行为。这是我的版本:
public bool IsCompleted=>Thread.CurrentThread.IsThreadPoolThread是的,检查SynchronizationContext确实有点奇怪:这表示任何旧的非调度程序线程,而不是特定的线程池线程。
await ThreadSwitcher.ResumeBackgroundAsync();