How to async this long running method?

2019-04-11 21:19发布

问题:

I have this method which I would like to run asynchronously so that I can do other things while it runs. It does not rely on any other Async method (it doesn't call out to another resource, download a file or anything). I would like to avoid using new Task(), Task.Factory.StartTask() and Task.Run(), if possible.

Is it possible to run this method asynchronously, with tidy, readable code and without using Task explicitly?

If not, what is the tidiest way of running the method asynchronously?

Note: Please don't be concerned with the silly logic in the method - I have boiled it down to be deliberately slow but not show my actual code.

public static void main(string[] args)
{
  RunMySlowLogic();
}

private void RunMySlowLogic()
{
  while (true)
    for (int i=0; i<100000000;i++)
      if (i == new Random().Next(999))
        return true;
}

Currently, I believe that I would need to wrap the method in a lambda or Task and mark it async. Where would the await go?

回答1:

You're confusing two different things. You can run this in the background, and this method can be asynchronous. These are 2 different things and your method can do either, or both.

If you do something asynchronous in that method, like Task.Delay or some non-blocking I/O then call that method, await the returned task and make the method itself async:

async Task RunMySlowLogicAsync()
{
    while (true)
    {
        // ...
        await Task.Delay(1000);
    }
}

If you don't have such a thing then your method isn't asynchronous, it's synchronous. You can still run it in the background on a different (ThreadPool) thread while you do other things using Task.Run:

var task = Task.Run(() => RunMySlowLogic());


回答2:

There are multiple ways of executing code asynchronously in the .NET environment. Have a look at the Asynchronous Programming Patterns MSDN article.

Tasks are to make your job easier. I think the only valid reason to avoid using tasks is when you are targeting an older version of .NET.

So without Tasks, you can start a thread yourself, or use a ThreadPool (Tasks do this internally).

public static void main(string[] args)
{
  var are = new AutoResetEvent(false);
  ThreadPool.QueueUserWorkItem(RunMySlowLogicWrapped, are);
  // Do some other work here
  are.WaitOne();
}

// you have to match the signature of WaitCallback delegate, we can use it to communicate cross-thread
private void RunMySlowLogicWrapped(Object state) {
  AutoResetEvent are = (AutoResetEvent) state;
  RunMySlowLogic();
  are.Set();
}

private bool RunMySlowLogic() 
{
  while (true)
    for (int i=0; i<100000000;i++)
      if (i == new Random().Next(999))
        return true;
}