For details on usage see the associated blog post here.
Install either by downloading from asset store or from the releases section
A bunch of code to make using async-await easier in Unity3D
License: MIT License
For details on usage see the associated blog post here.
Install either by downloading from asset store or from the releases section
Seems Unity uses a lock()
a delegate/event is invoked which can result in more nightmare bug hunts so it needs to be addressed.
It looks like the lock()
is just used for having thread-safe collection access. Use the appropriate System.Collections.Concurrent
collection (Queue?) type instead of a lock()
statement while still having thread-safe collections.
If exclusive access is required, they might be able to use InterlockedExchange with a Boolean flag that is checked and set thread-safe with the Interlocked helper methods.
The task is to make the WaitForUpdate
thread-safe to avoid deadlock situations.
A coworker wrote:
One issue I noticed:
await WaitForUpdate()
posts to the Unity synchronization context. This shouldn't be a problem, butUnitySynchronizationContext
has a major problem in its implementation: it locks the message queue while it's executing messages. This means that if weawait WaitForUpdate()
, thenlock()
waiting for some other thread, and that other thread also doesawait WaitForUpdate()
, it'll deadlock because the event queue is locked while the sync context is executing. Bad Unity!
private void Exec()
{
lock (m_AsyncWorkQueue)
{
var workCount = m_AsyncWorkQueue.Count;
for (int i = 0; i < workCount; i++)
{
var work = m_AsyncWorkQueue.Dequeue();
work.Invoke();
}
}
}
See the problem there? Rule of thumb: Never call external events or delegates inside of a
lock()
Hello everyone!
I am having trouble using await
with a method from the Unity WebRTC implementation (I am using version 2.2.0-preview). Most methods which are supposed to be called in a coroutine seem to be working fine, but RTCPeerConnection.CreateAnswer()
returns null
when I use await
.
What I am doing is roughly this:
// WebRTC.Initialize() is already called
// The remoteDescription comes from my signaling server
this.localConnection = new RTCPeerConnection(ref rtcConfig);
await localConnection.SetRemoteDescription(ref remoteDescription);
var answerOptions = new RTCAnswerOptions { iceRestart = false };
var answer = await localConnection.CreateAnswer(ref answerOptions);
// After this answer == null
When I call CreateAnswer()
inside a Coroutine, I get a RTCSessionDescription
description as expected.
var answerOptions = new RTCAnswerOptions { iceRestart = false };
var answer = localConnection.CreateAnswer(ref answerOptions);
yield return answer;
// After the yield, anser is *not* null and contains a session description in answer.Desc
The return value of RTCPeerConnection.CreateAnswer
is a RTCSessionDescriptionAsyncOperation.
Do I need a special Awaiter here that is not covered by IEnumeratorAwaitExtensions
?
Any tipps and hints in the right direction would be greatly appreciated!
Thanks in advance for any insights you could provide on this issue and best regards,
Patrick
I'm trying to incrementally convert our codebase from coroutines to async/await. Doing it incrementally means a lot of "await " and "Task.AsIEnumerator()" to convert between the two styles at the boundaries.
One issue I've found is that converting a Coroutine -> async Task is not as simple as changing the method from "IEnumerator DoSomethingCoroutine()" -> "async Task DoSomethingAsync()" and fixing up callers to append ".AsIEnumerator()", because exceptions that propagate from Task and AsIEnumerator() are wrapped with AggregateException().
I'm assuming that the main use case of Task.AsIEnumerator is to help with the transition process, so I think there's a good argument for unwrapping the AggregateException. On the other hand, I'm not sure when the AggregateException might contain 2 or more exceptions and what AsIEnumerator should do in that case.
Here's some sample code that illustrates the issue:
class MyCustomException : Exception {}
IEnumerator<object> CallerCoroutine() {
// Old code is sometimes verbose, for call stacks and exception propagation
using (var cr = DoSomethingCoroutine()) {
while (true) {
try {
if (!cr.MoveNext()) { break; }
} catch (MyCustomException e) {
// ...
}
yield return cr.Current;
}
}
// Simple automated refactor doesn't work because the exception is now AggregateException
using (var cr = DoSomethingAsync().AsIEnumerator()) {
// ... body is same as above ...
}
}
IEnumerator<object> DoSomethingCoroutine() {
if (UnityEngine.Random.value > .5f) { throw new MyCustomException(); }
yield return null;
}
async Task<object> DoSomethingAsync() {
if (UnityEngine.Random.value > .5f) { throw new MyCustomException(); }
await Awaiters.NextFrame;
return null;
}
We're experiencing the Assert failing in the SimpleCoroutineAwaiter implementation of INotifyCompletion.OnCompleted.
We've also seen this error pop up many times before in random places. This particular part of the code is just waiting on a WaitForUpdate instance.
Unfortunately I don't have any other details, and I've not been able to reproduce this despite many attempts. As far as I can tell the generated task state machine code should only invoke the OnCompleted method once ever, so I really don't understand how this could happen.
System.Exception Assert hit in UnityAsyncUtil package!
0 IEnumeratorAwaitExtensions.Assert (System.Boolean condition) (<00000000000000000000000000000000>:0)
1 IEnumeratorAwaitExtensions+SimpleCoroutineAwaiter.System.Runtime.CompilerServices.INotifyCompletion.OnCompleted (System.Action continuation) (<00000000000000000000000000000000>:0)
2 System.Runtime.CompilerServices.AsyncVoidMethodBuilder.AwaitOnCompleted[TAwaiter,TStateMachine] (TAwaiter& awaiter, TStateMachine& stateMachine) (<00000000000000000000000000000000>:0)
3 ODDFramework.AdProviderBase+d__40.MoveNext () (<00000000000000000000000000000000>:0)
There are a lot of small memory allocs happening in a lot of areas. We avoid a lot of these allocs by using a static memory pool
Hey, really cool utility! Makes it really painless to use the new async/await features.
I noticed when I run my game I get the following warning in the console:
Assets/Plugins/AsyncAwaitUtil/Tests/AsyncUtilTests.cs(213,27): warning CS0618:
`UnityEngine.Networking.UnityWebRequest.Send()' is obsolete: `Use SendWebRequest.
It returns a UnityWebRequestAsyncOperation which contains a reference to the WebRequest object.'
Thank you for writing this beautiful piece of code! Can't find the licence though. Can you please specify that?
When the exception is cached and throw;
is not applicable, another technique is needed to preserve the original exception's context. Storing it as an InnerException
is one way, but I think in this case, it's more useful to rethrow it without changing its context:
ExceptionDispatchInfo.Capture(ex).Throw();
A pull request is on the way.
I've created this as an issue with Unity, as it is to do with their implementation of the SynchronizationContext
; but it appears setting Time.timeScale = 0f
delays the continuations being run on Unity's thread until it is increased above 0
.
We found this while using the provided new WaitForUpdate
/ Awaiters.NextFrame
from a background task.
Unity Ticket: 1057404
this method in C#
private async void DelayedFakeChat()
{
await new WaitForSeconds(1.0f);
_signalBus.Fire(...);
}
fails to build in an il2cpp build:
Bulk_Assembly-CSharp_1.cpp:21899:9: assigning to 'RuntimeObject *' (aka 'Il2CppObject *') from incompatible type 'U3CDelayedFakeChatU3Ed__51_t8460B8A56468D8BC08EE7C35ACAE8A2C8ABDECBE'
any ideas? should it even work on il2cpp?
i am on unity 2018.4.2
I hacked this by making SyncContextUtil.Install public and calling it in my tests SetUp method, but I don't know if there's a better way?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.