async Task RunDownloadAsync()
{
Debug.Log("Starting Download");
var result = await Task.Run(() => Download());
Debug.Log(result);
}
string Download()
{
Debug.Log("Downloading");
// Debug.Log(Random.Range(0, 100).ToString());
Debug.Log("Download Complete");
return "a cool movie";
}
Works exactly as expected:
When I uncomment the line where I print out a Random.Range number it stops right there. It doesn’t even print it out. When calling the method directly (result = Download()) it also works. But somehow Random.Range interferes with the task.
Can someone enlighten me (and gain the badge of being smarter than ChatGPT which is also confused why it’s not working )
I don’t see a “Done” at the end of your top screenshot… is that just because you added the code after snapping the screenshot? If not, then it seems to me you should see a “Done” and thus something isn’t working exactly as expected even in the first one…
async void StartRequest()
{
await RunDownloadAsync();
}
async Task RunDownloadAsync()
{
Debug.Log("Starting Download");
Debug.Log(Random.Range(0, 10002));
var result = await Task.Run(() => Download());
Debug.Log("done");
}
string Download()
{
Debug.Log("Downloading");
// simulate a long running task by doing a bunch of math
for (int i = 0; i < 1000000000; i++)
{
var x = i * i;
}
Debug.Log(Random.Range(0, 12));
Debug.Log("Download Complete");
return "a cool movie";
}
This does not throw an error but will never call Random.Range or anything that follows it. The app doesn’t crash and the main thread keeps running:
void StartRequest()
{
RunDownloadAsync();
}
async Task RunDownloadAsync()
{
Debug.Log("Starting Download");
Debug.Log(Random.Range(0, 10002));
var result = await Task.Run(() => Download());
Debug.Log("done");
}
string Download()
{
Debug.Log("Downloading");
// simulate a long running task by doing a bunch of math
for (int i = 0; i < 1000000; i++)
{
var x = i * i;
}
//log a random int
Debug.Log(Random.Range(0, 12));
Debug.Log("Download Complete");
return "a cool movie";
}
Playing around with await some more, I’m confused why this doesn’t use multi threading at all (game freezes until the method is done), but if I use the method below with running a task it works perfectly.
void StartRequest()
{
RunDownloadAsync();
Debug.Log("Task started but continuing with other stuff in the mean time");
}
async Task RunDownloadAsync()
{
Debug.Log("Starting Download");
await Download();
// await Task.Run(() => Download());
Debug.Log("done");
}
async Task<string> Download()
{
Debug.Log("Downloading");
// simulate a long running task by doing a bunch of math
for (int i = 0; i < 1000000000; i++)
{
var x = i * i;
}
Debug.Log("Download Complete");
return "a cool movie";
}
Async Await alone isn’t actually multithreaded, it’s a coroutine that is running on the main thread
As you can see here, Async Await and Coroutine behaviour is pretty much the same
Await Task.Yield of the async function and Yield return null of the coroutine both yield until the next frame, so the loops are being run over multiple frames.
void Start()
{
CountFramesAsync();
StartCoroutine(CountFramesCoroutine());
}
public async void CountFramesAsync()
{
for (int i = 0; i < 20; i++)
{
Debug.Log($"Async {Time.frameCount}");
await Task.Yield();
}
}
public IEnumerator CountFramesCoroutine()
{
for (int i = 0; i < 20; i++)
{
Debug.Log($"Coroutine {Time.frameCount}");
yield return null;
}
}
Without yielding in some form, your async function is just going to run like a normal function in the main thread until it is finished, the same is true with a coroutine. If you’re doing something that takes long, it will freeze the main thread, so you either have to break it up into smaller pieces by yielding, or you have to run that task in a different thread.
Task.Run is starting a new thread and running a function in that thread, which means it doesn’t need to yield to not freeze the main thread.
When you await the Task.Run your async function is yielding until the function in that other thread has finished, before it picks up where it left off.