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