搜索一个 Task.Yield 等价于线程池
Searching for a Task.Yield equivalent that yields to the thread pool
Task.Yield
方法 “创建一个可等待的任务,该任务在等待时异步返回到当前上下文。” 我正在寻找类似的东西,它应该保证任何随后的代码将在 ThreadPool
线程上 运行。我知道我可以通过将以下所有代码包含在 Task.Run
中来实现这一点,但我正在寻找不创建内部范围的内联解决方案。
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
与空委托一起使用,并将等待配置为 not 捕获同步上下文:
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
}
这看起来像是一行晦涩难懂的代码,我不确定它是否充分表达了存在的意图。我也不确定它是否提供了我想要的保证。还有其他解决办法吗?
顺便说一句,这个问题的灵感来自 Marc Gravell 的 to a related .
更新: 我应该给出更具体的原因,说明为什么使用标准 await Task.Run(() =>
在我的情况下并不理想。我有一些代码应该在 ThreadPool
上 运行 或不应该,这取决于某些条件。所以 Task.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
}
如果不重复代码,或者不添加 lambda 和间接寻址,我无法用 Task.Run
做同样的事情。
Raymond Chen 在他的博客 The Old New Thing in the post C++/WinRT envy: Bringing thread switching tasks to C# (WPF and WinForms edition).
中发布了此事
转载于此,以防源失效:
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();
}
这让您可以:
await ThreadSwitcher.ResumeBackgroundAsync();
我对在共享代码库中实际执行此操作持谨慎态度:它不是特别地道,而 Task.Run
非常清楚。
Task.Yield
方法 “创建一个可等待的任务,该任务在等待时异步返回到当前上下文。” 我正在寻找类似的东西,它应该保证任何随后的代码将在 ThreadPool
线程上 运行。我知道我可以通过将以下所有代码包含在 Task.Run
中来实现这一点,但我正在寻找不创建内部范围的内联解决方案。
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
与空委托一起使用,并将等待配置为 not 捕获同步上下文:
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
}
这看起来像是一行晦涩难懂的代码,我不确定它是否充分表达了存在的意图。我也不确定它是否提供了我想要的保证。还有其他解决办法吗?
顺便说一句,这个问题的灵感来自 Marc Gravell 的
更新: 我应该给出更具体的原因,说明为什么使用标准 await Task.Run(() =>
在我的情况下并不理想。我有一些代码应该在 ThreadPool
上 运行 或不应该,这取决于某些条件。所以 Task.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
}
如果不重复代码,或者不添加 lambda 和间接寻址,我无法用 Task.Run
做同样的事情。
Raymond Chen 在他的博客 The Old New Thing in the post C++/WinRT envy: Bringing thread switching tasks to C# (WPF and WinForms edition).
中发布了此事转载于此,以防源失效:
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(); }
这让您可以:
await ThreadSwitcher.ResumeBackgroundAsync();
我对在共享代码库中实际执行此操作持谨慎态度:它不是特别地道,而 Task.Run
非常清楚。