Deep understanding of Unity coroutines

Coroutines are supported in many programming languages. For example, in Lua we mentioned earlier, coroutines are a virtual threading technology.


Brief description


Think about what we usually mentioned when buying a computer. The cpu is four cores and eight threads. In fact, the cpu can only handle one thing. That is to say, the cpu defaults to one core for one thread, but if we need to process multiple Tasks, and we do n’t have that many threads.
Then people put forward the concept of virtual threads, virtualize a single thread of the CPU, and create multiple threads, so that we have the concepts of four cores and eight threads, eight cores and sixteen threads; there are also threads on the application side. And the concept of process, after subdividing the process, the thread of the virtualization software has the concept of coroutine.

By now you know that coroutines are the subdivision of threads, and they are the re-virtualization of threads.

 Unity coroutine


Although the concept of coroutines is not novel, the term "coroutines" may rarely be involved in the current Internet development field.
Coroutine is to work together to accomplish one thing. It is easy to think of the concept of multi-threading. For example, when we make a network request, we need to wait for the response before the next operation. At this time, we will use `mutexes` and` threads Security` etc. concept.
In unity or in the game engine, due to the constraints of the main loop thread of the game, it is impossible to ensure the safety of multithreading. At this time, it is particularly important to continue to use coroutines to undertake multithreading work under the same thread.
(Unity also withdrew from the performance-first ECS mode, abandoned the Mono framework, and implemented a development mode that can be assisted by multi-threaded development.)
Next, we will mainly introduce the unity coroutines in detail.

 Unity coroutine example


Look at this example:

//创建协程
private IEnumerator Cor1()
{
    yield return new WaitForSeconds(2f);
    Debug.Log("2s到了");
}
//启动协程
StartCoroutine(Cor1());


This is a simple example, you can see that the coroutine needs to return an `IEnumerator` iterable object, which was originally the implementation of the iterator pattern in Csharp, and Unity implemented the coroutine as a prototype in unity.

 Parameters of coroutines


In the above we used `new WaitForSeconds ()`, which means waiting for the specified time. [Note that WaitForSeconds is related to Time.Scale]
There are many parameters other than WaitForSeconds used above. These parameters either take time or return bool. In short, you need to determine a moveNext.


Usage of coroutines

 

1. Used for situations of uncertain duration (for example: network requests, reading and writing files)
2. For delayed execution
3. Can be used as a simple timer (for example: producing a batch of enemies)

 Coroutine nesting


Coroutines support nesting. The following is a simple implementation of patrol using coroutines.
** Note: In unity, the coroutine returns 0 or null to wait for the next frame. **

using System;
using System.Collections;
using UnityEngine;

namespace Coroutines
{
    //协程测试
    public class CoroutTest : MonoBehaviour
    {
        public Transform[] wayPoints;

        private bool isLoop;

        private void Start()
        {
            isLoop = true;
            StartCoroutine(StartLoop());
        }

        private IEnumerator StartLoop()
        {
            do
            {
                foreach (var point in wayPoints)
                {
                    yield return StartCoroutine(MoveTarget(point.position));
                }
            } while (isLoop);
        }

        private IEnumerator MoveTarget(Vector3 target)
        {
            while (transform.position!=target)
            {
                transform.position = Vector3.MoveTowards(transform.position, target, 3 * Time.deltaTime);
                yield return 0;
            }
        }
    }
}


 Let the coroutine move

 

+ StartCoroutine (nameof (StartLoop));
start the coroutine in the form of a string, can stop the coroutine externally, and cannot pass parameters.

+ StartCoroutine (StartLoop);
start coroutine in the form of iterator, can pass parameters, can not stop coroutine with stop externally.

### Stop the
coroutine The coroutine is essentially an iterator. When moveNext is false, all items in the coroutine have been executed.
There are several ways to stop coroutines in unity:

1. StopCoroutine () Note that this method can only stop the coroutine started in the form of a string [used outside the coroutine]
2. yield break out of the coroutine [used inside the coroutine]
3. Stop it through logic The execution condition of the process is not satisfied]
4. Set the object to be inactive [activate the coroutine again will not be restored]
5. StopAllCoroutine () Terminate all coroutines

As in the coroutine nesting example above, if we want the coroutine to stop:
1. Set isLoop = false; let it stop automatically if it does not meet the conditions after it is executed once
2. Break inside the coroutine
 

if (transform.position==wayPoints[2].position)
{
    yield break;
}


3. Stop outside the coroutine
 

 StopCoroutine(nameof(StartLoop));

 The design idea of ​​coroutine

 Does coroutine replace update?


Through the above example, you can find that coroutines are actually another implementation of update. We can even use coroutines without any update and fixedUpdate to complete the writing of the program.
But if we do this, is it not the case? Coroutines are a paradigm of delayed execution introduced by unity, which is still based on the upper layer of update.

Will using coroutines greatly improve program efficiency?


No, coroutines are essentially on one thread. Although multiple coroutines can be parallelized, these coroutines always run on one thread, and the speed and efficiency will not be greatly improved. Instead, multiple threads are opened in parallel, and the thread needs to monitor the state of many coroutines. When a large number of coroutines finish, it will trigger a large number of GC recovery, which may reduce the efficiency of the program.

 to sum up


A coroutine is a thread running on a thread, and its operation mode is still based on a single thread, and it will not improve the operating efficiency of the program because of the use of coroutines, but the convenient way of writing coroutines and the powerful functions can improve us as developers. Development efficiency.
In a sense, coroutines are more like a beautiful syntactic sugar

Published 25 original articles · Likes6 · Visits 10,000+

Guess you like

Origin blog.csdn.net/qq_37446649/article/details/105647645