From 82219e6111183f6a3e3b0d2bd600fe9f4952c3e1 Mon Sep 17 00:00:00 2001 From: neuecc Date: Thu, 18 Jun 2020 03:28:03 +0900 Subject: [PATCH] Fix UniTask.Delay does not run on threadpool thread --- .../Runtime/Linq/UnityExtensions/Timer.cs | 4 +- .../UniTask/Runtime/PlayerLoopHelper.cs | 2 + .../Plugins/UniTask/Runtime/UniTask.Delay.cs | 8 +- .../Assets/Scenes/ExceptionExamples.cs | 65 +--- src/UniTask/Assets/Tests/DelayTest.cs | 304 +++++++++--------- src/UniTask/Assets/Tests/RunTest.cs | 4 +- 6 files changed, 177 insertions(+), 210 deletions(-) diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/UnityExtensions/Timer.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/UnityExtensions/Timer.cs index a4869b2..53ecfcd 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/UnityExtensions/Timer.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/UnityExtensions/Timer.cs @@ -100,7 +100,7 @@ namespace Cysharp.Threading.Tasks.Linq if (this.period <= 0) this.period = 1; } - this.initialFrame = Time.frameCount; + this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; this.dueTimePhase = true; this.updateTiming = updateTiming; this.ignoreTimeScale = ignoreTimeScale; @@ -220,7 +220,7 @@ namespace Cysharp.Threading.Tasks.Linq if (periodFrameCount <= 0) periodFrameCount = 1; } - this.initialFrame = Time.frameCount; + this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; this.dueTimePhase = true; this.dueTimeFrameCount = dueTimeFrameCount; this.periodFrameCount = periodFrameCount; diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopHelper.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopHelper.cs index 13fec6c..18fa074 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopHelper.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopHelper.cs @@ -94,6 +94,8 @@ namespace Cysharp.Threading.Tasks public static int MainThreadId => mainThreadId; internal static string ApplicationDataPath => applicationDataPath; + public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == mainThreadId; + static int mainThreadId; static string applicationDataPath; static SynchronizationContext unitySynchronizationContetext; diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs index 4ebedf2..1df46cb 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs @@ -214,7 +214,7 @@ namespace Cysharp.Threading.Tasks result = new NextFramePromise(); } - result.frameCount = Time.frameCount; + result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); @@ -313,7 +313,7 @@ namespace Cysharp.Threading.Tasks result.delayFrameCount = delayFrameCount; result.cancellationToken = cancellationToken; - result.initialFrame = Time.frameCount; + result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; TaskTracker.TrackActiveTask(result, 3); @@ -429,7 +429,7 @@ namespace Cysharp.Threading.Tasks result.elapsed = 0.0f; result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds; result.cancellationToken = cancellationToken; - result.initialFrame = Time.frameCount; + result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; TaskTracker.TrackActiveTask(result, 3); @@ -538,7 +538,7 @@ namespace Cysharp.Threading.Tasks result.elapsed = 0.0f; result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds; - result.initialFrame = Time.frameCount; + result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); diff --git a/src/UniTask/Assets/Scenes/ExceptionExamples.cs b/src/UniTask/Assets/Scenes/ExceptionExamples.cs index d69cfc1..da2c538 100644 --- a/src/UniTask/Assets/Scenes/ExceptionExamples.cs +++ b/src/UniTask/Assets/Scenes/ExceptionExamples.cs @@ -1,77 +1,28 @@ -// Provided from: https://github.com/Cysharp/UniTask/issues/40 - -using System; +using System; using System.Threading.Tasks; using Cysharp.Threading.Tasks; using UnityEngine; +using UnityEngine.Networking; -/// -/// Example script for comparing how exceptions in unobserved tasks are handled between -/// UniTask and normal tasks. This helps in verifying that unobserved exceptions are -/// logged in a way that it useful to developers. -/// public class ExceptionExamples : MonoBehaviour { - [SerializeField] private LogType _unobservedExceptionLogType = LogType.Exception; - - private void Awake() - { - UniTaskScheduler.UnobservedExceptionWriteLogType = _unobservedExceptionLogType; - } - + private void Start() { - UnityEngine.Debug.Log("ExceptionScene, LoopType:" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount); //TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; //ThrowFromAsyncVoid(); //_ = ThrowFromTask(); //_ = ThrowFromUniTask(); - + //ThrowFromNonAsync(); } - private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) + public static async Task Test() { - UnityEngine.Debug.LogException(e.Exception); - } - - private void ThrowFromNonAsync() - { - throw new Exception("Thrown from non-async function"); - } - - private async void ThrowFromAsyncVoid() - { - await ThrowInner(); - - async Task ThrowInner() - { - await UniTask.Yield(); - throw new Exception("Thrown from `async void` function"); - } - } - - private async Task ThrowFromTask() - { - await ThrowInner(); - - async Task ThrowInner() - { - await UniTask.Yield(); - throw new Exception("Thrown from `async Task` function"); - } - } - - private async UniTask ThrowFromUniTask() - { - await ThrowInner(); - - async UniTask ThrowInner() - { - await UniTask.Yield(); - throw new Exception("Thrown from `async UniTask` function"); - } + var webRequest = UnityWebRequest.Get("http"); + var request = webRequest.SendWebRequest(); + await request; } } \ No newline at end of file diff --git a/src/UniTask/Assets/Tests/DelayTest.cs b/src/UniTask/Assets/Tests/DelayTest.cs index 2792af5..0a2352a 100644 --- a/src/UniTask/Assets/Tests/DelayTest.cs +++ b/src/UniTask/Assets/Tests/DelayTest.cs @@ -16,168 +16,180 @@ namespace Cysharp.Threading.TasksTests { public class DelayTest { - [UnityTest] - public IEnumerator DelayFrame() => UniTask.ToCoroutine(async () => - { - for (int i = 1; i < 5; i++) - { - await UniTask.Yield(PlayerLoopTiming.PreUpdate); - var frameCount = Time.frameCount; - await UniTask.DelayFrame(i); - Time.frameCount.Should().Be(frameCount + i); - } + //[UnityTest] + //public IEnumerator DelayFrame() => UniTask.ToCoroutine(async () => + //{ + // for (int i = 1; i < 5; i++) + // { + // await UniTask.Yield(PlayerLoopTiming.PreUpdate); + // var frameCount = Time.frameCount; + // await UniTask.DelayFrame(i); + // Time.frameCount.Should().Be(frameCount + i); + // } - for (int i = 1; i < 5; i++) - { - await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); - var frameCount = Time.frameCount; - await UniTask.DelayFrame(i); - Time.frameCount.Should().Be(frameCount + i); - } - }); + // for (int i = 1; i < 5; i++) + // { + // await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); + // var frameCount = Time.frameCount; + // await UniTask.DelayFrame(i); + // Time.frameCount.Should().Be(frameCount + i); + // } + //}); - [UnityTest] - public IEnumerator DelayFrameZero() => UniTask.ToCoroutine(async () => - { - { - await UniTask.Yield(PlayerLoopTiming.PreUpdate); - var frameCount = Time.frameCount; - await UniTask.DelayFrame(0); - Time.frameCount.Should().Be(frameCount); // same frame - } - { - await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); - var frameCount = Time.frameCount; - await UniTask.DelayFrame(0); - Time.frameCount.Should().Be(frameCount + 1); // next frame - } - }); + //[UnityTest] + //public IEnumerator DelayFrameZero() => UniTask.ToCoroutine(async () => + //{ + // { + // await UniTask.Yield(PlayerLoopTiming.PreUpdate); + // var frameCount = Time.frameCount; + // await UniTask.DelayFrame(0); + // Time.frameCount.Should().Be(frameCount); // same frame + // } + // { + // await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); + // var frameCount = Time.frameCount; + // await UniTask.DelayFrame(0); + // Time.frameCount.Should().Be(frameCount + 1); // next frame + // } + //}); - [UnityTest] - public IEnumerator TimerFramePre() => UniTask.ToCoroutine(async () => - { - await UniTask.Yield(PlayerLoopTiming.PreUpdate); + //[UnityTest] + //public IEnumerator TimerFramePre() => UniTask.ToCoroutine(async () => + //{ + // await UniTask.Yield(PlayerLoopTiming.PreUpdate); - var initialFrame = Time.frameCount; - var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync(); + // var initialFrame = Time.frameCount; + // var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync(); - xs[0].Should().Be(initialFrame + 2); - xs[1].Should().Be(initialFrame + 2 + (3 * 1)); - xs[2].Should().Be(initialFrame + 2 + (3 * 2)); - xs[3].Should().Be(initialFrame + 2 + (3 * 3)); - xs[4].Should().Be(initialFrame + 2 + (3 * 4)); - }); + // xs[0].Should().Be(initialFrame + 2); + // xs[1].Should().Be(initialFrame + 2 + (3 * 1)); + // xs[2].Should().Be(initialFrame + 2 + (3 * 2)); + // xs[3].Should().Be(initialFrame + 2 + (3 * 3)); + // xs[4].Should().Be(initialFrame + 2 + (3 * 4)); + //}); + + + //[UnityTest] + //public IEnumerator TimerFramePost() => UniTask.ToCoroutine(async () => + //{ + // await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); + + // var initialFrame = Time.frameCount; + // var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync(); + + // xs[0].Should().Be(initialFrame + 2); + // xs[1].Should().Be(initialFrame + 2 + (3 * 1)); + // xs[2].Should().Be(initialFrame + 2 + (3 * 2)); + // xs[3].Should().Be(initialFrame + 2 + (3 * 3)); + // xs[4].Should().Be(initialFrame + 2 + (3 * 4)); + //}); + + + //[UnityTest] + //public IEnumerator TimerFrameTest() => UniTask.ToCoroutine(async () => + //{ + // await UniTask.Yield(PlayerLoopTiming.PreUpdate); + + // var initialFrame = Time.frameCount; + // var xs = await UniTaskAsyncEnumerable.TimerFrame(0, 0).Take(5).Select(_ => Time.frameCount).ToArrayAsync(); + + // xs[0].Should().Be(initialFrame); + // xs[1].Should().Be(initialFrame + 1); + // xs[2].Should().Be(initialFrame + 2); + // xs[3].Should().Be(initialFrame + 3); + // xs[4].Should().Be(initialFrame + 4); + //}); + + + //[UnityTest] + //public IEnumerator TimerFrameSinglePre() => UniTask.ToCoroutine(async () => + //{ + // { + // await UniTask.Yield(PlayerLoopTiming.PreUpdate); + // var initialFrame = Time.frameCount; + // var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync(); + // xs[0].Should().Be(initialFrame); + + // } + // { + // await UniTask.Yield(PlayerLoopTiming.PreUpdate); + // var initialFrame = Time.frameCount; + + // var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ => + // { + // var t = Time.frameCount; + + // return t; + // }).ToArrayAsync(); + + // xs[0].Should().Be(initialFrame + 1); + // } + // { + // await UniTask.Yield(PlayerLoopTiming.PreUpdate); + // var initialFrame = Time.frameCount; + // var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync(); + // xs[0].Should().Be(initialFrame + 2); + // } + //}); + + + //[UnityTest] + //public IEnumerator TimerFrameSinglePost() => UniTask.ToCoroutine(async () => + //{ + // { + // //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); + // //var initialFrame = Time.frameCount; + // //var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync(); + // //xs[0].Should().Be(initialFrame); + // } + // { + // //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); + // var initialFrame = Time.frameCount; + // var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ => Time.frameCount).ToArrayAsync(); + // xs[0].Should().Be(initialFrame + 1); + // } + // { + // //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); + // var initialFrame = Time.frameCount; + // var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync(); + // xs[0].Should().Be(initialFrame + 2); + // } + //}); + + + + //[UnityTest] + //public IEnumerator Timer() => UniTask.ToCoroutine(async () => + //{ + // await UniTask.Yield(PlayerLoopTiming.PreUpdate); + + // { + // var initialSeconds = Time.realtimeSinceStartup; + // var xs = await UniTaskAsyncEnumerable.Timer(TimeSpan.FromSeconds(2)).Select(_ => Time.realtimeSinceStartup).ToArrayAsync(); + + // Mathf.Approximately(initialSeconds, xs[0]).Should().BeFalse(); + // Debug.Log("Init:" + initialSeconds); + // Debug.Log("After:" + xs[0]); + // } + //}); [UnityTest] - public IEnumerator TimerFramePost() => UniTask.ToCoroutine(async () => + public IEnumerator DelayInThreadPool() => UniTask.ToCoroutine(async () => { - await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); + await UniTask.Run(async () => + { + Debug.Log("Go Delay?"); - var initialFrame = Time.frameCount; - var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync(); + await UniTask.Delay(TimeSpan.FromSeconds(2)); - xs[0].Should().Be(initialFrame + 2); - xs[1].Should().Be(initialFrame + 2 + (3 * 1)); - xs[2].Should().Be(initialFrame + 2 + (3 * 2)); - xs[3].Should().Be(initialFrame + 2 + (3 * 3)); - xs[4].Should().Be(initialFrame + 2 + (3 * 4)); + Debug.Log("OK?"); + }); }); - [UnityTest] - public IEnumerator TimerFrameTest() => UniTask.ToCoroutine(async () => - { - await UniTask.Yield(PlayerLoopTiming.PreUpdate); - - var initialFrame = Time.frameCount; - var xs = await UniTaskAsyncEnumerable.TimerFrame(0, 0).Take(5).Select(_ => Time.frameCount).ToArrayAsync(); - - xs[0].Should().Be(initialFrame); - xs[1].Should().Be(initialFrame + 1); - xs[2].Should().Be(initialFrame + 2); - xs[3].Should().Be(initialFrame + 3); - xs[4].Should().Be(initialFrame + 4); - }); - - - [UnityTest] - public IEnumerator TimerFrameSinglePre() => UniTask.ToCoroutine(async () => - { - { - await UniTask.Yield(PlayerLoopTiming.PreUpdate); - var initialFrame = Time.frameCount; - var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync(); - xs[0].Should().Be(initialFrame); - - } - { - await UniTask.Yield(PlayerLoopTiming.PreUpdate); - var initialFrame = Time.frameCount; - - var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ => - { - var t = Time.frameCount; - - return t; - }).ToArrayAsync(); - - xs[0].Should().Be(initialFrame + 1); - } - { - await UniTask.Yield(PlayerLoopTiming.PreUpdate); - var initialFrame = Time.frameCount; - var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync(); - xs[0].Should().Be(initialFrame + 2); - } - }); - - - [UnityTest] - public IEnumerator TimerFrameSinglePost() => UniTask.ToCoroutine(async () => - { - { - //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); - //var initialFrame = Time.frameCount; - //var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync(); - //xs[0].Should().Be(initialFrame); - } - { - //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); - var initialFrame = Time.frameCount; - var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ => Time.frameCount).ToArrayAsync(); - xs[0].Should().Be(initialFrame + 1); - } - { - //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); - var initialFrame = Time.frameCount; - var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync(); - xs[0].Should().Be(initialFrame + 2); - } - }); - - - - [UnityTest] - public IEnumerator Timer() => UniTask.ToCoroutine(async () => - { - await UniTask.Yield(PlayerLoopTiming.PreUpdate); - - { - var initialSeconds = Time.realtimeSinceStartup; - var xs = await UniTaskAsyncEnumerable.Timer(TimeSpan.FromSeconds(2)).Select(_ => Time.realtimeSinceStartup).ToArrayAsync(); - - Mathf.Approximately(initialSeconds, xs[0]).Should().BeFalse(); - Debug.Log("Init:" + initialSeconds); - Debug.Log("After:" + xs[0]); - } - }); - - - - } diff --git a/src/UniTask/Assets/Tests/RunTest.cs b/src/UniTask/Assets/Tests/RunTest.cs index 7397372..b9f6f7f 100644 --- a/src/UniTask/Assets/Tests/RunTest.cs +++ b/src/UniTask/Assets/Tests/RunTest.cs @@ -78,7 +78,9 @@ namespace Cysharp.Threading.TasksTests var main = Thread.CurrentThread.ManagedThreadId; try { - await UniTask.Run(() => throw new Exception(), true); +#pragma warning disable CS1998 + await UniTask.Run(async () => throw new Exception(), true); +#pragma warning restore CS1998 } catch {