多线程列表模式建议
Multi-threading list pattern advice
我制作了一个包含 folder/file 扫描仪的应用程序。我遇到了线程结构的问题。
工作原理:
对于每个 folder/file 它发现它启动一个线程。每个线程内都有一个函数,它使用一个列表来检查是否找到了类似的项目,以便它可以添加到现有项目中。如果没有找到,它会将项目添加到前面提到的列表中。线程并行执行(异步)。
问题:
因为它是异步的,所以它有时会在列表检查中失败。这是因为检查和添加到列表之间有一个时间段。可能发生的事情是检查 returns 没有类似的项目,而确实有。这将导致相同的项目出现在列表中。
我也让线程互相等待。我真的很喜欢它在前端带来的效果。 (项目很好地实时添加到列表中)。但这需要很长时间 folders/files.
现在我正在考虑混合使用这些函数,但我真的很想看到异步线程的速度和每个线程等待的安全性的结合。
有人知道吗?
您应该锁定检查列表并添加值的整个代码部分。
像这样:
private void YourThreadMethod(object state)
{
// long taking operation
lock (dictionary)
{
if (!dictionary.ContainsKey(yourItemKey))
{
// construct object, long taking operation
dictionary.Add(yourItemKey, createdObject);
}
}
}
这样一来,每个线程都得等到list
空闲了才可以使用。如果您想要更高级的解决方案,您可以阅读 ReaderWriterLockSlim
class,它提供了更细粒度的解决方案。
我会考虑使用 C# 中的 thread safe collections 之一。对于您的情况,ConcurrentBag
之类的东西比使用锁更有效。
如果检查和添加之间存在时间延迟,您可以使用ConcurrentDictionary
。它有一个 TryAdd 方法,如果字典中已经存在具有相同键的项目,该方法将 return false
。
最圆滑的方法是在 yourItemKey
是 string
类型时使用 ConcurrentDictionary<string, byte>
(otherwise adapt TKey
and use a proper IEqualityComparer
or implement IEquatable):
private readonly ConcurrentDictionary<string, byte> _list = new ConcurrentDictionary<string, byte>();
private void Foo(object state)
{
// looong operation
this._list.TryAdd(yourItemKey, 0);
}
public void Bar()
{
// this is how to query the content
this._list.Keys...;
}
这背后的诀窍是不要使用太复杂的对象作为键,它可能需要处理或具有外部引用(我更喜欢任何字符串表示),以及一个小类型的值,它只是作用作为标记。
我制作了一个包含 folder/file 扫描仪的应用程序。我遇到了线程结构的问题。
工作原理: 对于每个 folder/file 它发现它启动一个线程。每个线程内都有一个函数,它使用一个列表来检查是否找到了类似的项目,以便它可以添加到现有项目中。如果没有找到,它会将项目添加到前面提到的列表中。线程并行执行(异步)。
问题: 因为它是异步的,所以它有时会在列表检查中失败。这是因为检查和添加到列表之间有一个时间段。可能发生的事情是检查 returns 没有类似的项目,而确实有。这将导致相同的项目出现在列表中。
我也让线程互相等待。我真的很喜欢它在前端带来的效果。 (项目很好地实时添加到列表中)。但这需要很长时间 folders/files.
现在我正在考虑混合使用这些函数,但我真的很想看到异步线程的速度和每个线程等待的安全性的结合。
有人知道吗?
您应该锁定检查列表并添加值的整个代码部分。
像这样:
private void YourThreadMethod(object state)
{
// long taking operation
lock (dictionary)
{
if (!dictionary.ContainsKey(yourItemKey))
{
// construct object, long taking operation
dictionary.Add(yourItemKey, createdObject);
}
}
}
这样一来,每个线程都得等到list
空闲了才可以使用。如果您想要更高级的解决方案,您可以阅读 ReaderWriterLockSlim
class,它提供了更细粒度的解决方案。
我会考虑使用 C# 中的 thread safe collections 之一。对于您的情况,ConcurrentBag
之类的东西比使用锁更有效。
如果检查和添加之间存在时间延迟,您可以使用ConcurrentDictionary
。它有一个 TryAdd 方法,如果字典中已经存在具有相同键的项目,该方法将 return false
。
最圆滑的方法是在 yourItemKey
是 string
类型时使用 ConcurrentDictionary<string, byte>
(otherwise adapt TKey
and use a proper IEqualityComparer
or implement IEquatable):
private readonly ConcurrentDictionary<string, byte> _list = new ConcurrentDictionary<string, byte>();
private void Foo(object state)
{
// looong operation
this._list.TryAdd(yourItemKey, 0);
}
public void Bar()
{
// this is how to query the content
this._list.Keys...;
}
这背后的诀窍是不要使用太复杂的对象作为键,它可能需要处理或具有外部引用(我更喜欢任何字符串表示),以及一个小类型的值,它只是作用作为标记。