Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 什么';从列表中添加/删除特定项目的最佳方式<;T>;在多线程场景中_C#_Concurrency - Fatal编程技术网

C# 什么';从列表中添加/删除特定项目的最佳方式<;T>;在多线程场景中

C# 什么';从列表中添加/删除特定项目的最佳方式<;T>;在多线程场景中,c#,concurrency,C#,Concurrency,我现在有一个场景,需要在多线程条件下添加和删除项 我在做什么 lock(list) { if(!list.Contains(item)) { list.Add(Item); } } 及 但是我现在在比赛条件上有一个很大的问题。锁定时间正在增加和增加 我希望我可以使用ConcurrentBag,但它没有Contains方法,因此我无法删除我要删除的特定项 我现在使用ConcurrentDiciary作为临时解决方案。但这绝对不是正确的方法 所以我的问题是如

我现在有一个场景,需要在多线程条件下添加和删除项

我在做什么

lock(list)
{
    if(!list.Contains(item))
    {
        list.Add(Item);
    }
}

但是我现在在比赛条件上有一个很大的问题。锁定时间正在增加和增加

我希望我可以使用ConcurrentBag,但它没有Contains方法,因此我无法删除我要删除的特定项

我现在使用ConcurrentDiciary作为临时解决方案。但这绝对不是正确的方法


所以我的问题是如何解决这个问题?像这样的东西有没有无锁的实现?因为并发名称空间下的集合都不适合此问题。

只需为锁定控件创建一个无意义的对象:

object listLock = new object();

lock(listLock)
{
    if(!list.Contains(item))
    {
        list.Add(Item);
    }
}

我相信这通常是执行锁定的标准方法,因为您已经描述了上述问题。

您需要的是的并发版本
ConcurrentBag
不是为了这个,而是为了支持高效的生产者-消费者场景。框架中没有这样的集合

所以,正如您所说,您可以使用
ConcurrentDictionary
。但我同意你的观点,这不是一个理想的解决方案

或者,您可以将使用
List
的锁定代码替换为使用
HashSet
的锁定代码。像
Contains()
Remove()
这样的操作在大型列表上可能非常慢。但它们在散列集中应该是快速的,如果集合足够大,这将显著提高性能


也可能有第三方库包含类似于
ConcurrentHashSet
的内容,但我不知道任何内容。

虽然这比锁定列表好,但它并没有解决问题。如果锁定额外的锁定对象与锁定列表本身有什么区别?在这种情况下不是也有同样的效果吗?我不太明白为什么更好?由于对其执行操作的对象是一个简单的列表,因此我想说,拥有另一个对象只会增加复杂性。我建议仅当其他地方的代码可能对需要锁定的对象执行不相关的操作时,才使用另一个对象。如果列表已公开,则仍需要公开同步对象,用户将需要使用该对象。不是很好的设计,因为其他程序员需要知道这一点。您最好公开一个复制列表函数,或者添加/删除锁定列表的方法。顺便说一句,而不是我对答案的否决票。在许多其他情况下,使用同步对象是很好的。我认为您需要解释为什么
ConcurrentDictionary
不适合您的情况,因为我们会更好地了解问题所在。顺便说一句,这可能只是问题中的一个输入错误,但您的删除有一个错误,您不希望在包含检查中使用否定。是的,这是一个输入错误,我会编辑它。对于ConcurrentDictionary,因为没有键,只有对象。因此,如果我想使用ConcurrentDiciary,它就像ConcurrentDictionary一样,锁争用发生在哪里?添加/删除相当快,因此这不太可能是您被阻止的地方(除非您进行了大量的添加/删除)。您是否在锁内某处枚举集合,并对元素执行长时间运行的操作?如果是这样,您可以通过创建副本(在锁中)然后在副本上枚举(在锁外)来获得更好的性能。在旁注中,您可以调用Remove,而无需执行包含检查;如果没有要删除的内容,它只会返回false。@user696604当然,但我猜锁定时间会随着集合的大小而增加,因为在列表中查找项是O(n),而在字典中查找项是O(1)。列表。删除也是一个线性搜索。谢谢你的回复,我想我会坚持一段时间。顺便说一句,你们知道列表中的contains方法是如何实现的吗?不要告诉我它在迭代整个列表XD@liiir1985这就是我在评论你原来的帖子时说的。
Contains
Remove
都是线性搜索,因此是O(n)。刚刚测试了HashSet,它确实解决了这个问题,非常感谢。所以我想我会等着看是否有第三方并发版本
object listLock = new object();

lock(listLock)
{
    if(!list.Contains(item))
    {
        list.Add(Item);
    }
}