When to use TaskEx.Run vs. TaskEx.RunEx

13,277

Solution 1

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

Solution 2

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.

Share:
13,277

Related videos on Youtube

poco
Author by

poco

Updated on June 04, 2022

Comments

  • poco
    poco almost 2 years

    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();
            }
        }
    
  • Sandra
    Sandra about 12 years
    Actually that's not true... RunEx has to do with value returning lambda expressions... not asynchrony. Run handles async lambda's just fine.
  • svick
    svick about 12 years
    In .Net 4.5 DP, there seems to be only Task.Run(), no Exes.
  • Phil
    Phil about 12 years
    TaskEx is in the CTP only. In .Net 4.5 the methods on TaskEx have been integrated into Task.
  • Stephen Cleary
    Stephen Cleary about 12 years
    @svick, @Phil: In .NET 4.5, TaskEx.Run becomes an overload of Task.Run, and TaskEx.RunEx also becomes an overload of Task.Run.
  • Stephen Cleary
    Stephen Cleary about 12 years
    @Firoso: RunEx performs an unwrapping of the inner task. If you pass an async lambda to Run in VS2010, it will work "just fine" -- if you don't care about when it completes. However, if you want the returned Task to complete when the async lambda completes, then use TaskEx. See this blog post or this blog post for more info.