在没有异常处理的方法中使用 SemaphoreSlim
Use SemaphoreSlim in method without exception handling
目前,我正在为 "locking" "parts" 的 SemaphoreSlim
实现而苦苦挣扎,该方法必须是线程安全的。我的问题是,在没有异常处理过载的情况下实现它是非常困难的。因为在 "lock" 释放之前抛出异常,它将永远留在那里。
这是一个例子:
private SemaphoreSlim _syncLock = new SemaphoreSlim(1);
private IDictionary<string, string> dict = new Dictionary<string, string>();
public async Task ProcessSomeThing(string input)
{
string someValue = await GetSomeValueFromAsyncMethod(input);
await _syncLock.WaitAsync();
dict.Add(input, someValue);
_syncLock.Release();
}
如果多次输入相同的值,此方法将抛出异常,因为具有相同键的项将被添加到字典中两次,并且 "lock" 不会被释放。
假设我有很多 _syncLock.Release();
和 _syncLock.Release();
,很难写出 try-catch
或 .ContainsKey
或其他东西。这将完全破坏代码...是否可以在抛出 Exception
get 或离开某个术语时始终释放锁?
希望大家清楚我 asking/looing 的目的。
谢谢大家!
您可以只使用lock
,因为保护区内没有await
。处理所有这些。
如果不是这种情况,您要么需要在任何地方使用 try-finally
,要么编写一个自定义的一次性对象,以便您可以使用 using
.
的范围性质
我建议不要 使用lock
或SemaphoreSlim
。相反,使用正确的工具来完成工作——在这种情况下,使用 ConcurrentDictionary<TKey, Lazy<TValue>>
over the use of IDictionary<string, string>
and locking and semaphore's. There have been several articles about this pattern year's ago, here's one of the them 似乎是合适的。因此,遵循这个建议的模式将如下所示:
private ConcurrentDictionary<string, Lazy<Task<string>>> dict =
new ConcurrentDictionary<string, Lazy<Task<string>>>();
public Task ProcessSomeThing(string input)
{
return dict.AddOrUpdate(
input,
key => new Lazy<Task<string>>(() =>
GetSomeValueFromAsyncMethod(key),
LazyThreadSafetyMode.ExecutionAndPublication),
(key, existingValue) => new Lazy<Task<string>>(() =>
GetSomeValueFromAsyncMethod(key), // unless you want the old value
LazyThreadSafetyMode.ExecutionAndPublication)).Value;
}
最终,这实现了 线程安全 的目标 asynchronously
添加到您的 dictionary
。假设您的 GetSomeValueFromAsyncMethod
函数中有一个 try / catch
,错误处理会如您所料发生。更多资源:
- Why does ConcurrentDictionary.GetOrAdd(key, valueFactory) allow the valueFactory to be invoked twice?
- http://softwareblog.alcedo.com/post/2012/01/11/Sometimes-being-Lazy-is-a-good-thing.aspx
目前,我正在为 "locking" "parts" 的 SemaphoreSlim
实现而苦苦挣扎,该方法必须是线程安全的。我的问题是,在没有异常处理过载的情况下实现它是非常困难的。因为在 "lock" 释放之前抛出异常,它将永远留在那里。
这是一个例子:
private SemaphoreSlim _syncLock = new SemaphoreSlim(1);
private IDictionary<string, string> dict = new Dictionary<string, string>();
public async Task ProcessSomeThing(string input)
{
string someValue = await GetSomeValueFromAsyncMethod(input);
await _syncLock.WaitAsync();
dict.Add(input, someValue);
_syncLock.Release();
}
如果多次输入相同的值,此方法将抛出异常,因为具有相同键的项将被添加到字典中两次,并且 "lock" 不会被释放。
假设我有很多 _syncLock.Release();
和 _syncLock.Release();
,很难写出 try-catch
或 .ContainsKey
或其他东西。这将完全破坏代码...是否可以在抛出 Exception
get 或离开某个术语时始终释放锁?
希望大家清楚我 asking/looing 的目的。
谢谢大家!
您可以只使用lock
,因为保护区内没有await
。处理所有这些。
如果不是这种情况,您要么需要在任何地方使用 try-finally
,要么编写一个自定义的一次性对象,以便您可以使用 using
.
我建议不要 使用lock
或SemaphoreSlim
。相反,使用正确的工具来完成工作——在这种情况下,使用 ConcurrentDictionary<TKey, Lazy<TValue>>
over the use of IDictionary<string, string>
and locking and semaphore's. There have been several articles about this pattern year's ago, here's one of the them 似乎是合适的。因此,遵循这个建议的模式将如下所示:
private ConcurrentDictionary<string, Lazy<Task<string>>> dict =
new ConcurrentDictionary<string, Lazy<Task<string>>>();
public Task ProcessSomeThing(string input)
{
return dict.AddOrUpdate(
input,
key => new Lazy<Task<string>>(() =>
GetSomeValueFromAsyncMethod(key),
LazyThreadSafetyMode.ExecutionAndPublication),
(key, existingValue) => new Lazy<Task<string>>(() =>
GetSomeValueFromAsyncMethod(key), // unless you want the old value
LazyThreadSafetyMode.ExecutionAndPublication)).Value;
}
最终,这实现了 线程安全 的目标 asynchronously
添加到您的 dictionary
。假设您的 GetSomeValueFromAsyncMethod
函数中有一个 try / catch
,错误处理会如您所料发生。更多资源:
- Why does ConcurrentDictionary.GetOrAdd(key, valueFactory) allow the valueFactory to be invoked twice?
- http://softwareblog.alcedo.com/post/2012/01/11/Sometimes-being-Lazy-is-a-good-thing.aspx