搜索产生线程池的Task.Yield等效项 [英] Searching for a Task.Yield equivalent that yields to the thread pool

查看:28
本文介绍了搜索产生线程池的Task.Yield等效项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Task.Yield 方法"创建一个可等待的任务,该任务在等待时异步地返回当前上下文." 我正在寻找类似的东西,这些东西应保证后面的任何代码都会在 ThreadPool 线程上运行.我知道可以通过将以下所有代码包含在 Task.Run 中来实现此目的,但是我正在寻找不会创建内部作用域的内联解决方案.

The Task.Yield method "creates an awaitable task that asynchronously yields back to the current context when awaited." I am searching for something similar that should guarantee that any code that follows will run on a ThreadPool thread. I know that I could achieve this be enclosing all the following code in a Task.Run, but I am searching for an inline solution that doesn't create an inner scope.

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
    });
}

我能想到的最好的方法是将 Task.Run 与空的委托一起使用,并将等待配置为捕获同步上下文:

The best I can think of is to use the Task.Run with an empty delegate, and configure the awaiting to not capture the synchronization context:

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
}

这看起来像是一句晦涩难懂的代码,而且我不确定这是否足以表达在那里的意图.我也不确定它是否提供我想要的保证.还有其他解决方案吗?

This looks like an obscure line of code, and I am not sure that expresses well enough the intent of being there. I am also not sure if it provides the guarantees I want. Is there any other solution?

顺便说一句,这个问题的灵感来自马克·格雷夫(Marc Gravell)的 answer到相关的问题.

Btw this question is inspired by a Marc Gravell's answer to a related question.

更新:对于我为什么不适合使用标准 await Task.Run(()=> )的原因,我应该给出一个更具体的原因.某些条件下,某些代码应该在 ThreadPool 上运行或不运行,因此等效于 Task.Yield 可以使我做到这一点:

Update: I should give a more specific reason about why using the standard await Task.Run(() => is not ideal in my case. I have some code that should run on the ThreadPool or not, depending on some condition. So a Task.Yield equivalent would allow me to do this:

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
}

如果没有代码重复或没有添加lambda和间接调用,我无法对 Task.Run 做同样的事情.

I can't do the same thing with Task.Run without code duplication, or without adding lambdas and indirection.

推荐答案

Raymond Chen在他的博客帖子 C ++/WinRT令人羡慕:带来线程切换任务到C#(WPF和WinForms版).

Raymond Chen posted about this in his blog The Old New Thing in the post C++/WinRT envy: Bringing thread switching tasks to C# (WPF and WinForms edition).

如果源掉了,请在此处复制:

Reproduced here in case the source goes down:

using System;
using System.Runtime.CompilerServices;
using System.Threading;          // For ThreadPool
using System.Windows.Forms;      // For Windows Forms
using System.Windows.Threading;  // For WPF

// For WPF
struct DispatcherThreadSwitcher : INotifyCompletion
{
    internal DispatcherThreadSwitcher(Dispatcher dispatcher) =>
        this.dispatcher = dispatcher;
    public DispatcherThreadSwitcher GetAwaiter() => this;
    public bool IsCompleted => dispatcher.CheckAccess();
    public void GetResult() { }
    public void OnCompleted(Action continuation) =>
        dispatcher.BeginInvoke(continuation);
    Dispatcher dispatcher;
}

// For Windows Forms
struct ControlThreadSwitcher : INotifyCompletion
{
    internal ControlThreadSwitcher(Control control) =>
        this.control = control;
    public ControlThreadSwitcher GetAwaiter() => this;
    public bool IsCompleted => !control.InvokeRequired;
    public void GetResult() { }
    public void OnCompleted(Action continuation) =>
        control.BeginInvoke(continuation);
    Control control;
}

// For both WPF and Windows Forms
struct ThreadPoolThreadSwitcher : INotifyCompletion
{
    public ThreadPoolThreadSwitcher GetAwaiter() => this;
    public bool IsCompleted =>
        SynchronizationContext.Current == null;
    public void GetResult() { }
    public void OnCompleted(Action continuation) =>
        ThreadPool.QueueUserWorkItem(_ => continuation());
}

class ThreadSwitcher
{
    // For WPF
    static public DispatcherThreadSwitcher ResumeForegroundAsync(
        Dispatcher dispatcher) =>
        new DispatcherThreadSwitcher(dispatcher);

    // For Windows Forms
    static public ControlThreadSwitcher ResumeForegroundAsync(
        Control control) =>
        new ControlThreadSwitcher(control);

    // For both WPF and Windows Forms
    static public ThreadPoolThreadSwitcher ResumeBackgroundAsync() =>
         new ThreadPoolThreadSwitcher();
}

这可让您执行以下操作:

This lets you do:

await ThreadSwitcher.ResumeBackgroundAsync();


但是,我会在共享代码库中实际执行此操作时要小心:这不是特别习惯,而 Task.Run 非常清楚.

这篇关于搜索产生线程池的Task.Yield等效项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆