同步访问单例对象初始化
Synchronise access to singleton object initialisation
我正在从 dotnet 核心 Web 应用程序访问 EventStore。所有线程共享一个连接。连接在第一次访问时打开,我需要确保只有一个线程打开连接。以前我会使用 lock
但后来我无法 await
打开连接的方法。
我发现 following snippet 代码看起来应该可以解决问题:
public class AsyncLock : IDisposable
{
private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
public async Task<AsyncLock> LockAsync()
{
await _semaphoreSlim.WaitAsync().ConfigureAwait(false);
return this;
}
public void Dispose()
{
_semaphoreSlim.Release();
}
}
并在我的代码中使用它:
private static readonly AsyncLock _mutex = new AsyncLock();
private volatile bool _isConnected = false;
private async Task EstablishConnected()
{
if (!_isConnected)
{
using (await _mutex.LockAsync())
{
if (!_isConnected)
{
await _connection.ConnectAsync().ConfigureAwait(false);
_isConnected = true;
}
}
}
}
这是一种同步访问 initialise/open EventStore 连接的合理方法吗?
原来有一个有用的 nuget library and associated Github repo from Stephen Cleary 可以替代上面的 AsyncLock
class。
我觉得你的做法是合理的。但是,如果您正在寻找管理初始化的异步方式,请查看 Microsoft.VisualStudio.Threading 包中的一些可用对象,例如 AsyncLazy
。我不认为该包可用于 .NET 核心,但 source code 在 github 上并且在 MIT 许可下。
使用 AsyncLazy,你可以做这样的事情:
public class MyEventStoreConsumer
{
private static readonly Func<Task<IEventStoreConnection>> getConnection;
static MyEventStoreConsumer()
{
var eventStore = EventStoreConnection.Create(...);
var connection = new AsyncLazy<IEventStoreConnection>(async () =>
{
await eventStore.ConnectAsync().ConfigureAwait(false);
return eventStore;
});
getConnection = () => connection.GetValueAsync();
}
}
我正在从 dotnet 核心 Web 应用程序访问 EventStore。所有线程共享一个连接。连接在第一次访问时打开,我需要确保只有一个线程打开连接。以前我会使用 lock
但后来我无法 await
打开连接的方法。
我发现 following snippet 代码看起来应该可以解决问题:
public class AsyncLock : IDisposable
{
private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
public async Task<AsyncLock> LockAsync()
{
await _semaphoreSlim.WaitAsync().ConfigureAwait(false);
return this;
}
public void Dispose()
{
_semaphoreSlim.Release();
}
}
并在我的代码中使用它:
private static readonly AsyncLock _mutex = new AsyncLock();
private volatile bool _isConnected = false;
private async Task EstablishConnected()
{
if (!_isConnected)
{
using (await _mutex.LockAsync())
{
if (!_isConnected)
{
await _connection.ConnectAsync().ConfigureAwait(false);
_isConnected = true;
}
}
}
}
这是一种同步访问 initialise/open EventStore 连接的合理方法吗?
原来有一个有用的 nuget library and associated Github repo from Stephen Cleary 可以替代上面的 AsyncLock
class。
我觉得你的做法是合理的。但是,如果您正在寻找管理初始化的异步方式,请查看 Microsoft.VisualStudio.Threading 包中的一些可用对象,例如 AsyncLazy
。我不认为该包可用于 .NET 核心,但 source code 在 github 上并且在 MIT 许可下。
使用 AsyncLazy,你可以做这样的事情:
public class MyEventStoreConsumer
{
private static readonly Func<Task<IEventStoreConnection>> getConnection;
static MyEventStoreConsumer()
{
var eventStore = EventStoreConnection.Create(...);
var connection = new AsyncLazy<IEventStoreConnection>(async () =>
{
await eventStore.ConnectAsync().ConfigureAwait(false);
return eventStore;
});
getConnection = () => connection.GetValueAsync();
}
}