How do I make non-essential computations run in th

2019-06-28 02:24发布

问题:

This question is in follow up to Why is this code running synchronously? . I realize that my real question is at a higher level than the one in that post. The question I now ask, below, is "how do I accomplish this?"

I want to use concurrency in C# to compute things in the background. I have class ptsTin, which represents an existing ground surface. I want to make loading as fast as possible. Some of the work is essential in that you don't have an instance until the work is complete. For example, there is no ptsTin instance until .LoadPoints() and .LoadTriangles are both complete.

Other parts of the work are not essential and may be computed later, even if later is 0.2 seconds later. I would like to start the non-essential work in a new thread and forget about it. If the value that it is working on is not ready yet, the value will just be null.

So here is what I would like to do. The code is now in a console app, but one day will be in a GUI app. Note, this is pseudo code. I know it will not work like this, and its purpose is to communicate what I want to know how to do:

  static void Main(string[] args)
  {
      var myTin = ptsDTM.Load("SomeFile.ptsTin");
      // Do other stuff here like getElevationAtAPoint();
  }

  public static ptsTin Load(String file)
  {
     // Essential Work
     ptsTin newTin = new ptsTin();
     newTin.LoadPoints(file);
     newTin.LoadTriangles(file);

     // At this point I could return, but I want other stuff done
     // Non-essential work -- I want this on a "background" task
     newTin.BoundingBox = newTin.ComputeBBInTheBackground();    

     // Now return without waiting for ComputeBB to finish
     return newTin;
  }

If another method later asks for tin.BoundingBox, but the value is not ready yet, it is still null. Other methods will know that the value is valid when it is not null.

How do I accomplish this?

I have no preference whether or not the answer is to use async and await, Task.Run, or any other approach.

回答1:

How do I accomplish this?

You can do this by changing BoundingBox to a Task<BoundingBox> which will be completed in the future.

public static ptsTin Load(String file)
{
    // Essential Work
    ptsTin newTin = new ptsTin();
    newTin.LoadPoints(file);
    newTin.LoadTriangles(file);

    // At this point I could return, but I want other stuff done
    // Non-essential work -- I want this on a "background" task
    newTin.BoundingBox = Task.Run(() => newTin.ComputeBB());

    // Now return without waiting for ComputeBB to finish
    return newTin;
}

Now, you can look up the status in other methods:

if (ptsTin.BoundingBox.Status == TaskStatus.Completed)
{
     // Finished computing
}