Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use TaskEx.Run vs. TaskEx.RunEx

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();
        }
    }
like image 343
poco Avatar asked Feb 17 '12 20:02

poco


2 Answers

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:

  • Potential pitfalls to avoid when passing around async lambdas
  • Task.Run vs Task.Factory.StartNew

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 simple async methods, and only use Run/RunEx if you need to run something in the background.

like image 88
Stephen Cleary Avatar answered Oct 21 '22 06:10

Stephen Cleary


The difference between your two DoWork() methods is that the first one (that uses TaskEx.RunEx()) is not asynchronous at all. It executes fully synchronously, starts the other task on another thread, and immediately returns a completed Task. If you awaited or Wait()ed on that task, it wouldn't wait until the internal task is completed.

like image 20
svick Avatar answered Oct 21 '22 06:10

svick