Hi! current AsyncOperationBase.Task property implementation use WaitHandler and start completely new thread just to wait on it. This implementation is far not optimal because of wasting thread from thread pool for blocking wait.
Current implementation:
System.Threading.EventWaitHandle m_waitHandle;
internal System.Threading.WaitHandle WaitHandle
{
get
{
if (m_waitHandle == null)
m_waitHandle = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset);
m_waitHandle.Reset();
return m_waitHandle;
}
}
internal System.Threading.Tasks.Task<TObject> Task
{
get
{
#if UNITY_WEBGL
Debug.LogError("Multithreaded operation are not supported on WebGL. Unable to aquire Task.");
return default;
#else
if (Status == AsyncOperationStatus.Failed)
{
return System.Threading.Tasks.Task.FromResult(default(TObject));
}
if (Status == AsyncOperationStatus.Succeeded)
{
return System.Threading.Tasks.Task.FromResult(Result);
}
var handle = WaitHandle;
return System.Threading.Tasks.Task.Factory.StartNew((Func<object, TObject>)(o =>
{
var asyncOperation = o as AsyncOperationBase<TObject>;
if (asyncOperation == null)
return default(TObject);
handle.WaitOne();
return (TObject)asyncOperation.Result;
}), this);
#endif
}
internal void InvokeCompletionEvent()
{
if (m_CompletedActionT != null)
{
m_CompletedActionT.Invoke(new AsyncOperationHandle<TObject>(this));
m_CompletedActionT.Clear();
}
if (m_waitHandle != null)
m_waitHandle.Set();
m_InDeferredCallbackQueue = false;
}
}
What do you think about changing implementation to use TaskComletionSource? With it code above could be rewrite to something like this
System.Threading.Tasks.TaskCompletionSource<TObject> m_taskCompletionSource;
internal System.Threading.Tasks.TaskCompletionSource<TObject> TaskCompletionSource
{
get
{
if (m_taskCompletionSource == null)
m_taskCompletionSource = new System.Threading.Tasks.TaskCompletionSource<TObject>();
return m_taskCompletionSource;
}
}
internal System.Threading.Tasks.Task<TObject> Task
{
get
{
if (Status == AsyncOperationStatus.Failed)
{
return System.Threading.Tasks.Task.FromResult(default(TObject));
}
if (Status == AsyncOperationStatus.Succeeded)
{
return System.Threading.Tasks.Task.FromResult(Result);
}
return TaskCompletionSource.Task;
}
}
internal void InvokeCompletionEvent()
{
if (m_CompletedActionT != null)
{
m_CompletedActionT.Invoke(new AsyncOperationHandle<TObject>(this));
m_CompletedActionT.Clear();
}
if (m_taskCompletionSource != null)
m_taskCompletionSource.SetResult(Result);
m_InDeferredCallbackQueue = false;
}
Pros: no threads wasting, reusing task instance, work on WebGL(no additional threads involved)
Cons: personally don’t see any