Different await Task.Run(async () to without only async

Markus Freitag 3,786 Reputation points
2023-07-30T18:38:54.31+00:00

Hello! What is different between the two methods? Yes one with Task.Run, the other not.

How do they differ? Each function works asynchronously, not waiting. I thought only with Task.Run a new thread is created.

Can you please give me an explanation, maybe post another example?

  var monitoringTask =  CurrentMonitoring.DoProcess2();  
  var monitoringTask =  await CurrentMonitoring.DoProcess1();

With await it would be waiting, but then synchronous, since I can't do anything else. Is that right?

What can I, what could I read out in the return object 'monitoringTask'?

Thanks for your help.

void DoWork();  // This method is CPU-bound.
await Task.Run(() => DoWork()); // wait and UI not blocked?
await Task.Run(() => DoWorkAsync()); // what can here different, sometimes I see name with Async
 

public async Task DoProcess1()
{
	string text = "DoProcess File monitoring";
	MyCancellationTokenSource = new CancellationTokenSource();
	var token = MyCancellationTokenSource.Token;
	token = MyCancellationTokenSource.Token;
	await Task.Run(async () =>
	{
		try
		{
			while (!token.IsCancellationRequested)
			{
				await Task.Delay(2000, token);
				TaskNew = GetNewOrder();
				Execute();
			}
		}
		catch (OperationCanceledException ocEx)
		{
			Log.Error($"[{text}] '{ocEx.Message}'  The OperationCanceledException was called.");
		}
		catch (Exception ex)
		{
			Log.Error($"[{text}] '{ex.Message}' normal exception");
		}
	});
}

public async Task DoProcess2()
{
	string text = "DoProcess File monitoring";
	MyCancellationTokenSource = new CancellationTokenSource();
	var token = MyCancellationTokenSource.Token;

	try
	{
		while (!token.IsCancellationRequested)
		{
			// Delay for 2 seconds or until cancellation is requested
			await Task.Delay(2000, token);

			// Check again for cancellation before executing the task
			if (!token.IsCancellationRequested)
			{
				TaskNew = GetNewOrder();
				Execute();
			}
		}
	}
	catch (OperationCanceledException ocEx)
	{
		Log.Error($"[{text}] '{ocEx.Message}' The OperationCanceledException was called.");
	}
	catch (Exception ex)
	{
		Log.Error($"[{text}] '{ex.Message}' normal exception");
	}
}
Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,873 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,648 questions
{count} votes

Accepted answer
  1. Bruce (SqlWork.com) 61,731 Reputation points
    2023-07-31T20:48:07.3233333+00:00

    a method can return a Task. it is common to suffix these with Async.

    public Task DoSomthingAsync()
    {
       return Task.Run(() => Thread.Sleep(30000));
    }
    

    the calling thread can wait for its completion.

    DoSomthingAsync().Wait();
    DoSomethingElse(); 
    return;
    

    this blocks the current thread until the async thread completes. that is DoSomethingElse will not run until DoSomthingAsync() completes.

    but what if you did not want to block the main the thread, but still wanted DoSomethingElse() to run after DoSomthingAsync() completes. Then you use the Task.ContinueWith,

    DoSomthingAsync()
       .ContinueWith(() => DoSomethingElse()); 
    return;
    

    now the return will happen before the Task runs, and the DoSomethingElse() will run after DoSomethingElse

    to overlap another call its:

    DoSomthingAsync();
       .ContinueWith(() => DoSomethingElse()); 
    DoYetAnotherThingSync();
    return;
    

    here DoYetAnotherThingSync() will run on the main thread, while other work is done on a Task pool thread. the return will happen after DoYetAnotherThing() completes (but DoSomthingAsync() may still be running).

    if it was DoYetAnotherThingAsync(), two task thread would run and the return would happen before they completed,

    you can also overlap and block

    var task = DoSomthingAsync();
    DoYetAnotherThingSync();
    task.Wait(); // block thread to task completes
    return;
    

    as chaining become tedious and harder to read, especially if the ContinueWith is code rather than a single call

    DoSomthingAsync()
       .ContinueWith(() => DoSomethingElse1()) 
       .ContinueWith(() => DoSomethingElse2()) 
       .ContinueWith(() => DoSomethingElse3()) 
       .ContinueWith(() => DoSomethingElse4());
    return;
    

    c# added await keyword. The compiler just converts the code after the await to ContimeuWith()

    var i=0;
    await Task1();
    i++;
    await Task2();
    i++;
    await Task3();
    i++;
    return i;
    

    becomes:

    var i=0;
    Task1().ContinueWith(() =>
    {
      i++;
      return Task2().ContinueWith(() => 
      {
         i++;
         return Task3().ContinueWith(() =>
         {
            i++;
            return i;
         })
      })
    });
    

    as you can see the former is easier to read. for a method to use await(), it must return a Task and be prefixed with async:

    async Task<int> DoWorkAsync()
    {
        await Task1();
        await Task2();
    }
    

    now the call of DoWork(), has a couple options

    DoWorkAsync();       // fire and forget
    await DoWorkAsync(); // free thread while waiting (requires method returns task)
    DoWorkAsync().Wait();// block thread until complete
    

    note: one issue with UI and threads, is often the UI components can only be updated from the UI thread. in this the UI provides a way to execute code on the UI thread from another thread.


1 additional answer

Sort by: Most helpful
  1. SurferOnWww 2,491 Reputation points
    2023-07-31T01:02:04.28+00:00

    I understand that you are talking about ASP.NET programming.

    If so, please read the following Microsoft document:

    ASP.NET Core Best Practices

    It says in the "Avoid blocking calls" section as follows:

    "Do not call Task.Run and immediately await it. ASP.NET Core already runs app code on normal Thread Pool threads, so calling Task.Run only results in extra unnecessary Thread Pool scheduling."

    Also, please read the following Microsoft document to know how the thread pool is used in ASP.NET:

    Async Programming : Introduction to Async/Await on ASP.NET

    You will probably not have to consider "different between the two methods" as you will not use Task.Run in the ASP.NET programming.