Home > Mobile >  Can I create a C# async method without using a different thread (Task)?
Can I create a C# async method without using a different thread (Task)?

Time:05-31

I have searched a lot and it seems C# async await has to be used together with Task. The situation is that I have a method that is very time consuming which is OK, but I hope it won't block the main method.

So I describe the main method as "async", and inside it, I call and "await" the time consuming method, but C# need the time consuming method to be included in a Task which means it will be executed in a seperate thread. But that method has something that cannot run outside main thread.

And my question is how can I run the time consuming method asynchronously without putting it in a different thread?

Thank you very much.

PS: I'm doing this in Unity3D, is it possible to leverage Coroutine to reach the goal?

//main method
private async void MainMethod()
{
  //...
  bool result = await TimeConsumingMethod();
  //...
}

//time consuming method
private async Task<bool> TimeConsumingMethod()
{
  bool result;
  await Task.Run(()=> 
    {
      //...
      //SOME CODE THAT CANNOT run in thread other than main
      //...
    });
    return result;
}

CodePudding user response:

You may use Task<bool>.Run instead of Task. This way you can avoid additional methods.

public async Task MainMethod()
{
    Debug.Log("Before main thread.");
    
    var result = await Task<bool>.Run(async () =>
    {
        await Task.Delay(5000);
        
        Debug.Log("after 5 out sec");

        return true;
    });
    
    Debug.Log("After main thread: "   result);
}

Debug.Log("Before main thread.");

var result1 = Task<bool>.Run(async () =>
{
    await Task.Delay(5000);
    
    Debug.Log("result 1 end after 5 sec");

    return true;
});

var result2 = Task<bool>.Run(async () =>
{
    await Task.Delay(3000);
    
    Debug.Log("result 2 end after 3 sec");

    return true;
});

CodePudding user response:

To run anything aysnchronously (not blocking the main thread) in unity you have to use a different Thread/Task.

But as you also want to run code on the main thread in that separate thread you'll have to communicate between the two.

Although you can't run anything on the main thread from inside a different thread. You can make a queue that the main thread consistently handles. When the off thread then wants to do something on the main thread it adds it to the queue and the mainThreadHandler will then handle it in the next frame update. So the off thread can then tell the main thread that it wants to do something on the main thread and wait for the main thread to be done with that code and then continue with the processing after.

This is an implementation of a main thread handler:

public class MainThreadHandler:MonoBehaviour
{
    private static readonly Queue<Action> _executionQueue = new Queue<Action>();
    
    public void Update()
    {
        lock (_executionQueue)
        {
            while (_executionQueue.Count > 0)
            {
                _executionQueue.Dequeue().Invoke();
            }
        }
    }

    public static void Enqueue(Action action)
    {
        lock (_executionQueue)
        {
            _executionQueue.Enqueue(action);
        }
    }
}

Calling your code including calling things in the main thread and then waiting for it will then look something like this:

private Task currentTask;
private bool taskResult;

public void StartOffThreadMethod()
{
    currentTask = Task.Run(() =>
    {
        DoCalculationsOffThread();

        bool isMainThreadDone = false;
        MainThreadHandler.Enqueue(() =>
        {
            //Main thread code

            //Either set a bool that the off thread checks to see if the action has been completed
            //or start a new task that handles the rest of the off threaded code 
            //This example uses a isDone bool
            isMainThreadDone = true;
        });

        while (!isMainThreadDone)
        {
            Thread.Sleep(100);
        }

        DoOtherCalculationsOffThread();
        taskResult = true;
    });
}

private void Update()
{
    if (currentTask != null && currentTask.IsCompleted)
    {
        //do stuff with the result
    }
}

I'd also like to add that going back and forth between the main thread and an calculating thread can be rather tricky business. If it can be prevented i would try to prevent it.

  • Related