Guaranteeing Single Execution of Asynchronous Initialization in C#
This article addresses the challenge of ensuring a class's asynchronous initialization, via its InitializeAsync()
method, executes only once, even with concurrent calls from multiple threads.
One approach uses SemaphoreSlim
:
<code class="language-csharp">public class MyService : IMyService { private readonly SemaphoreSlim mSemaphore = new SemaphoreSlim(1, 1); private bool mIsInitialized; public async Task InitializeAsync() { if (!mIsInitialized) { await mSemaphore.WaitAsync(); if (!mIsInitialized) { await DoStuffOnlyOnceAsync(); mIsInitialized = true; } mSemaphore.Release(); } } private Task DoStuffOnlyOnceAsync() { return Task.Run(() => { Thread.Sleep(10000); }); } }</code>
A more elegant solution leverages AsyncLazy<T>
:
<code class="language-csharp">public class AsyncLazy<T> : Lazy<Task<T>> { public AsyncLazy(Func<T> valueFactory) : base(() => Task.Run(valueFactory)) { } public AsyncLazy(Func<Task<T>> taskFactory) : base(() => Task.Run(() => taskFactory())) { } public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); } }</code>
Usage example:
<code class="language-csharp">private AsyncLazy<bool> asyncLazy = new AsyncLazy<bool>(async () => { await DoStuffOnlyOnceAsync(); return true; });</code>
Note: A boolean placeholder is used because DoStuffOnlyOnceAsync()
lacks a return type.
For a refined AsyncLazy<T>
implementation, refer to Stephan Cleary's blog post: https://www.php.cn/link/366c0196895c9eeaa75992bacac60426
The above is the detailed content of How to Ensure Single Execution of Asynchronous Initialization in C#?. For more information, please follow other related articles on the PHP Chinese website!