How call async task in Unity
Hi. Prompt please how to create the asynchronous task in Unity? Unfortunately StartCoroutine not asynchronous operation. For example, I have the script creating 10000 cubes on a scene on clicking of the button. In an ideal, there still there shall be a blinking text about loading:
private bool myAsy = false;
void Start() {
myAsy = false;
}
void Update() {
if (myAsy) {
this.veryHardFunc();
myAsy = false;
}
}
void OnGUI() {
if (GUI.Button(new Rect(0, 0, 200, 100), "Asynccube")) {
myAsy = true;
}
}
//Very hard function - Execution time more than 1 second
publuc void veryHardFunc() {
GameObject conten = new GameObject();
conten.name = "01_contener";
for(int i = 0; i < 10000; i++) {
GameObject gmo = GameObject.CreatePrimitive(PrimitiveType.Cube);
gmo.name = "GMO" + i;
gmo.transform.parent = conten.parent;
}
}
Look at using a coroutine with yield return null;
, which means to wait until the next frame. It allows you to spread the work over several frames.
But, that myAsy variable does nothing useful. It's the same as if you just called veryHardFunc directly from the button.
@Owen-Reynolds I agree, probably not too successful example. But I simply wanted to show a situation. And if to do through Coroutine and, for example, to insert yield so:
for(int i = 0; i < 10000; i++) {
GameObject gmo = GameObject.CreatePrimitive(PrimitiveType.Cube);
gmo.name = "G$$anonymous$$O" + i;
gmo.transform.parent = conten.parent;
yield return null;
}
Then this task will be carried out 10000 frames. Whether is it impossible to learn somehow, whether there was still time in the current frame on execution of one more operation?
As JuiceIn notes, you can run a few before quitting for the frame: if(i%15==0) yield return break;
There can't be a way to check "how much time left in the frame," since this isn't the last thing you do. No way to be sure how much time drawing will take. Of course, true aSynch it wouldn't be an issue. But in practice trail&error on per-frame-loops works for me.
@Owen-Reynolds Thanks for the help. As I understand, for my task Coroutine should use. However, it is possible, there is other method. It is Application.LoadLevelAdditiveAsync (), beforehand having created the necessary scene. $$anonymous$$aybe it will work.
Answer by Juice-Tin · Jun 28, 2014 at 06:59 PM
What you ask is not possible, instead, make your script easier so it doesn't slow down unity:
void Start(){
amount = 0;
}
void Update(){
for(i; i < 10 && amount < 10000; i++) {
//Code here
gmo.name = "GMO" + amount;
}
}
This spreads out the workload over many frames. It may still take 1 second or perhaps slightly longer, but Unity will not freeze up while doing it, and other scripts will continue to run.
@Juice-Tin Unfortunately, me that task which I asked above interested. For example, I should remake level in real time. Then it is necessary to make a certain animation of the text("ChangeLevel") and gradually to remake level, deleting old gameObject and creating the new. Whether is it possible to realize it?
Answer by Kiwasi · Jun 28, 2014 at 08:25 PM
Unity is not threadsafe. Unity survives this by not allowing any threads other then the main thread to access Unity objects. Any Async operations cannot touch any Unity objects.
You can use Async operations for data processing, but they have to call back to the main thread when they are done.
Instantiating objects using another thread is not possible, you can cheat with coroutines as other posters have indicated.
Answer by BUWbrean · Dec 12, 2017 at 04:51 PM
Welcome to the future!
Unity 2017 has .Net 4.6 (Experimental) that allows you to use async and await for coroutines, take a look at this: http://www.stevevermeulen.com/index.php/2017/09/using-async-await-in-unity3d-2017/
Also there is a new Job system coming to Unity in 2018, that could help in the use case of the original author - take a look at this Unite Europe presentation: https://www.youtube.com/watch?v=AXUvnk7Jws4
(I know that it's been over 3 years since the first post, but it has made it quite high in my google search results for async code in Unity so I assume that other people will in the future find this and hope it will be useful.)
Answer by Ash-Blue · Jun 17, 2017 at 03:18 AM
You could complete what you're asking through an additive load operation of a scene with your cubes (generally how this is done).
https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadSceneAsync.html
Or you could offload your heavier computation logic onto a C# thread and let Unity only handle minor lifting of creation.
http://answers.unity3d.com/questions/357033/unity3d-and-c-coroutines-vs-threading.html
Concerning the fake coroutine as @Juice-Tin said to space out the number of cubes made per second. That will cause jittering due to heavy load over a short time on some computers (a solution that would probably produce very different results from system to system).
Your answer
Follow this Question
Related Questions
Save data async (and wait for it) from a coroutine 1 Answer
Load Scene in Background and Load When a Button is Clicked 0 Answers
How can I stop, start and reset a coroutine? 0 Answers
Stopping Couroutine 0 Answers
WaitForSeconds not working in C# 1 Answer