何时使用 TaskEx.Run 与 TaskEx.RunEx
我试图了解何时使用 TaskEx.Run
。我提供了下面编写的两个代码示例,它们产生相同的结果。我不明白的是为什么我会采用 Task.RunEx TaskEx.RunEx
方法,我确信有一个很好的理由,并且希望有人可以告诉我 。
async Task DoWork(CancellationToken cancelToken, IProgress<string> progress)
{
int i = 0;
TaskEx.RunEx(async () =>
{
while (!cancelToken.IsCancellationRequested)
{
progress.Report(i++.ToString());
await TaskEx.Delay(1, cancelToken);
}
}, cancelToken);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (button.Content.ToString() == "Start")
{
button.Content = "Stop";
cts.Dispose();
cts = new CancellationTokenSource();
listBox.Items.Clear();
IProgress<string> progress = new Progress<string>(s =>
{
listBox.Items.Add(s);
listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]);
});
DoWork(cts.Token, progress);
}
else
{
button.Content = "Start";
cts.Cancel();
}
}
我也能达到同样的结果
async Task DoWork(CancellationToken cancelToken)
{
int i = 0;
while (!cancelToken.IsCancellationRequested)
{
listBox.Items.Add(i++);
listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]);
await TaskEx.Delay(100, cancelToken);
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (button.Content.ToString() == "Start")
{
button.Content = "Stop";
cts.Dispose();
cts = new CancellationTokenSource();
listBox.Items.Clear();
DoWork(cts.Token);
}
else
{
button.Content = "Start";
cts.Cancel();
}
}
I'm trying to understand when to use TaskEx.Run
. I have provided two code sample i wrote below that produce the same result. What i fail to see is why i would take the Task.RunEx TaskEx.RunEx
approach, I'm sure there is a good reason and was hoping someone could fill me in.
async Task DoWork(CancellationToken cancelToken, IProgress<string> progress)
{
int i = 0;
TaskEx.RunEx(async () =>
{
while (!cancelToken.IsCancellationRequested)
{
progress.Report(i++.ToString());
await TaskEx.Delay(1, cancelToken);
}
}, cancelToken);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (button.Content.ToString() == "Start")
{
button.Content = "Stop";
cts.Dispose();
cts = new CancellationTokenSource();
listBox.Items.Clear();
IProgress<string> progress = new Progress<string>(s =>
{
listBox.Items.Add(s);
listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]);
});
DoWork(cts.Token, progress);
}
else
{
button.Content = "Start";
cts.Cancel();
}
}
I can achieve the same results like so
async Task DoWork(CancellationToken cancelToken)
{
int i = 0;
while (!cancelToken.IsCancellationRequested)
{
listBox.Items.Add(i++);
listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]);
await TaskEx.Delay(100, cancelToken);
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (button.Content.ToString() == "Start")
{
button.Content = "Stop";
cts.Dispose();
cts = new CancellationTokenSource();
listBox.Items.Clear();
DoWork(cts.Token);
}
else
{
button.Content = "Start";
cts.Cancel();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当您想要在线程池上下文中运行同步代码时,请使用TaskEx.Run。
当您想要在线程池上下文中运行异步代码时,请使用TaskEx.RunEx。
Stephen Toub 有两篇与行为差异相关的博客文章:
这是创建任务。如果您不必使用
Run
/RunEx
,那么您就不应该使用。使用简单的async
方法,并且仅在需要在后台运行某些内容时才使用Run
/RunEx
。Use
TaskEx.Run
when you want to run synchronous code in a thread pool context.Use
TaskEx.RunEx
when you want to run asynchronous code in a thread pool context.Stephen Toub has two blog posts related to the difference in behavior:
This is only one of several options you have for creating tasks. If you do not have to use
Run
/RunEx
, then you should not. Use simpleasync
methods, and only useRun
/RunEx
if you need to run something in the background.两个
DoWork()
方法之间的区别在于第一个方法(使用TaskEx.RunEx()
)根本不是异步的。它完全同步执行,在另一个线程上启动另一个任务,并立即返回已完成的任务。如果您对该任务进行await
或Wait()
,它不会等到内部任务完成。The difference between your two
DoWork()
methods is that the first one (that usesTaskEx.RunEx()
) is not asynchronous at all. It executes fully synchronously, starts the other task on another thread, and immediately returns a completedTask
. If youawait
ed orWait()
ed on that task, it wouldn't wait until the internal task is completed.据我了解,Task.Run 在大多数情况下都会生成一个新线程。
需要注意的是,仅仅因为您将方法标记为异步并使用等待程序,这并不(必然)意味着正在创建新线程,在许多情况下,完成被安排在调用它们的同一执行线程上。
这里的技巧与 SchedulingContext 有关。如果它是为多线程单元设置的,那么您将把完成委托给线程池上的可行线程。如果您像所有 WPF 和 WinForms UI 代码一样处于单线程单元中,那么它将返回到调用线程以完成,从而允许直接在 UI 上完成工作,而无需在代码中进行可见的线程编组。
Task.Run spawns a new thread in most scenarios as I understand it.
It's important to note that simply because you mark a method as async, and use awaiters, this does NOT (necessarily) mean that new threads are being created, completions are scheduled on the SAME thread of execution that they were called from in many cases.
The trick here has to do with the SchedulingContext. If it's set for a multithreaded apartment, then you're going to delegate completions to viable threads on the threadpool. If you're in a singlethreaded apartment as all WPF and WinForms UI code is, then it will return to the calling thread for completion allowing work to be done directly on the UI without visible thread marshalling in the code.