UniTask convert to coroutine which can not be stopped
`async UniTask TestOnStart2() { int cnt = 0; while(true) { cnt++; Debug.LogError("11111111"); await UniTask.Yield(); Debug.LogError("111122222"); if (cnt >= 10) { Debug.LogError("stop cor"); Scheduler.Instance.StopCoroutine(cor); }
}
}
IEnumerator cor; public async UniTaskVoid Start(Transform mainTransform) { var task2 = UniTask.Defer(async () => { await TestOnStart2(); }); cor = task2.ToCoroutine(); Debug.LogError("LazyStart"); Scheduler.Instance.StartCoroutine(cor); }`
run the code,and you will find that coroutine can not be stopped,how can I stop it?
Set the coroutine object to null after stopping it.
This test, based on your code, will succeed. However one extra iteration of the while loop will run after stopping the coutine.
Coroutine _coroutine;
int _counter = 0;
[SetUp]
public void SetUp() {
_coroutine = null;
_counter = 0;
}
[UnityTest]
public IEnumerator UniTaskToCoroutineTest() => UniTask.ToCoroutine(async () => {
_coroutine = CoroutineScheduler.Instance.StartCoroutine(AsyncCoroutineStopNull().ToCoroutine());
await UniTask.WaitUntil(() => _counter >= 10);
await UniTask.Delay(TimeSpan.FromSeconds(1));
Assert.That(_counter, Is.EqualTo(10));
});
async UniTask AsyncCoroutineStopNull() {
while (true) {
_counter++;
Debug.Log($"Tick {_counter}");
await UniTask.Yield();
if (_counter < 9) continue;
Debug.Log("Stopping Coroutine");
CoroutineScheduler.Instance.StopCoroutine(_coroutine);
_coroutine = null;
}
}
Where CoroutineScheduler is assumed to be this:
public class CoroutineScheduler : MonoBehaviour {
static CoroutineScheduler _instance;
public static CoroutineScheduler Instance => _instance ??= new GameObject(nameof(CoroutineScheduler)).AddComponent<CoroutineScheduler>();
}
Set the coroutine object to null after stopping it.
This test, based on your code, will succeed. However one extra iteration of the while loop will run after stopping the coutine.
Coroutine _coroutine; int _counter = 0; [SetUp] public void SetUp() { _coroutine = null; _counter = 0; } [UnityTest] public IEnumerator UniTaskToCoroutineTest() => UniTask.ToCoroutine(async () => { _coroutine = CoroutineScheduler.Instance.StartCoroutine(AsyncCoroutineStopNull().ToCoroutine()); await UniTask.WaitUntil(() => _counter >= 10); await UniTask.Delay(TimeSpan.FromSeconds(1)); Assert.That(_counter, Is.EqualTo(10)); }); async UniTask AsyncCoroutineStopNull() { while (true) { _counter++; Debug.Log($"Tick {_counter}"); await UniTask.Yield(); if (_counter < 9) continue; Debug.Log("Stopping Coroutine"); CoroutineScheduler.Instance.StopCoroutine(_coroutine); _coroutine = null; } }Where
CoroutineScheduleris assumed to be this:public class CoroutineScheduler : MonoBehaviour { static CoroutineScheduler _instance; public static CoroutineScheduler Instance => _instance ??= new GameObject(nameof(CoroutineScheduler)).AddComponent<CoroutineScheduler>(); }
yeah,it does work,thanks a lot,but why is there one extra running happening?
Loops in a UniTask cannot be stopped from the outside with StopCoroutine.
If you want to stop a UniTask from the outside, use CancellationTokenSource.
async UniTaskVoid Start()
{
var cts = new CancellationTokenSource();
var task = TestOnStart2(cts.Token);
// At any time of your choice.
cts.Cancel(); // < -- cancel the task.
}
async UniTask TestOnStart2(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Debug.Log("bra bra ..");
}
}