我制作了一个包含文件夹/文件扫描程序的应用程序。我遇到了线程结构的问题。
工作原理: 对于每个文件夹/文件,它找到它启动一个线程。每个线程中都有一个函数,它使用一个列表来检查是否找到了类似的项目,以便它可以添加到现有项目中。如果未找到,则会将该项添加到前面提到的列表中。线程是并行执行的(异步)。
问题: 因为它是异步的,所以它有时会在listcheck上失败。这是因为检查和添加到列表之间有一段时间。可能发生的事情是检查返回没有类似的项目,而肯定有。这将导致列表中出现相同的项目。
我还让线程彼此等待。我非常喜欢它在前端产生的效果。 (物品很好地实时添加到列表中)。但这需要很长时间才能获得很多文件夹/文件。
现在我正在考虑在函数之间进行混合,但我真的希望看到异步线程的速度和等待每个线程的安全性的组合。
有人有什么想法吗?
答案 0 :(得分:3)
您应该锁定检查列表的整个代码部分并添加值。
这样的事情:
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
类,它提供了更细粒度的解决方案。
答案 1 :(得分:2)
最恰当的方法是在ConcurrentDictionary<string, byte>
类型为yourItemKey
(otherwise adapt TKey
and use a proper IEqualityComparer
或implement IEquatable)时使用string
:
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...;
}
背后的诀窍是不要使用过于复杂的对象作为键,可能需要处理或有外部引用(我更喜欢任何字符串表示),以及一个小类型的值,它只是作为一个标记
答案 2 :(得分:0)
我会考虑使用C#中的thread safe collections之一。对于您的情况,像ConcurrentBag
这样的东西比使用锁更有效。
如果检查和添加之间存在时间延迟,您可以使用ConcurrentDictionary
。它有一个TryAdd方法,如果具有相同键的项已经在字典中,它将返回false
。