Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this code running synchronously?

I am trying to understand concurrency by doing it in code. I have a code snippet which I thought was running asynchronously. But when I put the debug writeline statements in, I found that it is running synchronously. Can someone explain what I need to do differently to push ComputeBB() onto another thread using Task.Something?

Clarification I want this code to run ComputeBB in some other thread so that the main thread will keep on running without blocking.

Here is the code:

{
    // part of the calling method
     Debug.WriteLine("About to call ComputeBB");
     returnDTM.myBoundingBox = await Task.Run(() => returnDTM.ComputeBB());
     Debug.WriteLine("Just called await ComputBB.");
     return returnDTM;
}

  private ptsBoundingBox2d ComputeBB()
  {
     Debug.WriteLine("Starting ComputeBB.");
     Stopwatch sw = new Stopwatch(); sw.Start();
     var point1 = this.allPoints.FirstOrDefault().Value;
     var returnBB = new ptsBoundingBox2d(
        point1.x, point1.y, point1.z, point1.x, point1.y, point1.z);
     Parallel.ForEach(this.allPoints,
        p => returnBB.expandByPoint(p.Value.x, p.Value.y, p.Value.z)
        );
     sw.Stop();
     Debug.WriteLine(String.Format("Compute BB took {0}", sw.Elapsed));
     return returnBB;
  }

Here is the output in the immediate window:

About to call ComputeBB
Starting ComputeBB.
Compute BB took 00:00:00.1790574
Just called await ComputBB.

Clarification If it were really running asynchronously it would be in this order:

About to call ComputeBB
Just called await ComputBB.
Starting ComputeBB.
Compute BB took 00:00:00.1790574

But it is not.

Elaboration The calling code has signature like so: private static async Task loadAsBinaryAsync(string fileName) At the next level up, though, I attempt to stop using async. So here is the call stack from top to bottom:

  static void Main(string[] args)
  {
      aTinFile = ptsDTM.CreateFromExistingFile("TestSave.ptsTin");
      // more stuff
  }

  public static ptsDTM CreateFromExistingFile(string fileName)
  {
     ptsDTM returnTin = new ptsDTM();
     Task<ptsDTM> tsk = Task.Run(() => loadAsBinaryAsync(fileName));
     returnTin = tsk.Result;  // I suspect the problem is here.
     return retunTin;
  }

  private static async Task<ptsDTM> loadAsBinaryAsync(string fileName)
  {
      // do a lot of processing
     Debug.WriteLine("About to call ComputeBB");
     returnDTM.myBoundingBox = await Task.Run(() => returnDTM.ComputeBB());
     Debug.WriteLine("Just called await ComputBB.");
     return returnDTM;
  }
like image 218
philologon Avatar asked May 04 '15 04:05

philologon


People also ask

What is a synchronous code?

Synchronous code runs in sequence. This means that each operation must wait for the previous one to complete before executing.

Why is it called synchronous programming?

However, in the context of programming, synchronous programming usually mean that instruction are executed one at a time(so not happening at the same time).

What is the difference between synchronous and asynchronous code?

The differences between asynchronous and synchronous include: Async is multi-thread, which means operations or programs can run in parallel. Sync is single-thread, so only one operation or program will run at a time. Async is non-blocking, which means it will send multiple requests to a server.

What is synchronous method?

When a synchronous method is invoked, it completes executing before returning to the caller. An asynchronous method starts a job in the background and returns to the caller immediately. Synchronous Methods. A typical synchronous method returns the result directly to the caller as soon as it completes executing.


1 Answers

I have a code snippet which I thought was running asynchronously. But when I put the debug writeline statements in, I found that it is running synchronously.

await is used to asynchronously wait an operations completion. While doing so, it yields control back to the calling method until it's completion.

what I need to do differently to push ComputeBB() onto another thread

It is already ran on a thread pool thread. If you don't want to asynchronously wait on it in a "fire and forget" fashion, don't await the expression. Note this will have an effect on exception handling. Any exception which occurs inside the provided delegate would be captured inside the given Task, if you don't await, there is a chance they will go about unhandled.

Edit:

Lets look at this piece of code:

public static ptsDTM CreateFromExistingFile(string fileName)
{
   ptsDTM returnTin = new ptsDTM();
   Task<ptsDTM> tsk = Task.Run(() => loadAsBinaryAsync(fileName));
   returnTin = tsk.Result;  // I suspect the problem is here.
   return retunTin;
}

What you're currently doing is synchronously blocking when you use tsk.Result. Also, for some reason you're calling Task.Run twice, once in each method. That is unnecessary. If you want to return your ptsDTM instance from CreateFromExistingFile, you will have to await it, there is no getting around that. "Fire and Forget" execution doesn't care about the result, at all. It simply wants to start whichever operation it needs, if it fails or succeeds is usually a non-concern. That is clearly not the case here.

You'll need to do something like this:

private PtsDtm LoadAsBinary(string fileName)
{
   Debug.WriteLine("About to call ComputeBB");
   returnDTM.myBoundingBox = returnDTM.ComputeBB();
   Debug.WriteLine("Just called ComputeBB.");

   return returnDTM;
}

And then somewhere up higher up the call stack, you don't actually need CreateFromExistingFiles, simply call:

Task.Run(() => LoadAsBinary(fileName));

When needed.

Also, please, read the C# naming conventions, which you're currently not following.

like image 84
Yuval Itzchakov Avatar answered Oct 14 '22 05:10

Yuval Itzchakov