我正在编写一个多线程程序来抓取某个站点并收集ID。它将这些ID存储在共享的静态List<string>
对象中。
当任何项目添加到List<string>
时,首先会针对包含已收集ID的黑名单的HashSet<string>
进行检查。
我这样做如下:
private static HashSet<string> Blacklist = new HashSet<string>();
private static List<string> IDList = new List<string>();
public static void AddIDToIDList(string ID)
{
lock (IDList)
{
if (IsIDBlacklisted(ID))
return;
IDList.Add(ID);
}
}
public static bool IsIDBlacklisted(string ID)
{
lock (Blacklist)
{
if (Blacklist.Contains(ID))
return true;
}
return false;
}
黑名单在完成后保存到文件中,并在每次程序启动时加载,因此,随着时间的推移它会变得非常大(最多50k记录)。有没有更有效的方法来不仅存储这个黑名单,还要检查每个ID?
谢谢!
答案 0 :(得分:3)
要提高性能,请尝试使用ConcurrentBag<T>
集合。此外,没有必要锁定BlackList,因为它没有被修改,例如:
private static HashSet<string> Blacklist = new HashSet<string>();
private static ConcurrentBag<string> IDList = new ConcurrentBag<string>();
public static void AddIDToIDList(string ID)
{
if (Blacklist.Contains(ID))
{
return;
}
IDList.Add(ID);
}
答案 1 :(得分:2)
读取操作在HashSet上是线程安全的,只要Blacklist
未被修改,您就不需要锁定它。此外,你应该锁定黑名单检查,以减少锁定,这也会提高你的表现。
private static HashSet<string> Blacklist = new HashSet<string>();
private static List<string> IDList = new List<string>();
public static void AddIDToIDList(string ID)
{
if (IsIDBlacklisted(ID))
return;
lock (IDList)
{
IDList.Add(ID);
}
}
public static bool IsIDBlacklisted(string ID)
{
return Blacklist.Contains(ID);
}
如果正在修改Blacklist
,锁定它的最佳方法是使用ReaderWriterLock(如果您使用较新的.NET,请使用slim version)
private static HashSet<string> Blacklist = new HashSet<string>();
private static List<string> IDList = new List<string>();
private static ReaderWriterLockSlim BlacklistLock = new ReaderWriterLockSlim();
public static void AddIDToIDList(string ID)
{
if (IsIDBlacklisted(ID))
return;
lock (IDList)
{
IDList.Add(ID);
}
}
public static bool IsIDBlacklisted(string ID)
{
BlacklistLock.EnterReadLock();
try
{
return Blacklist.Contains(ID);
}
finally
{
BlacklistLock.ExitReadLock();
}
}
public static bool AddToIDBlacklist(string ID)
{
BlacklistLock.EnterWriteLock();
try
{
return Blacklist.Add(ID);
}
finally
{
BlacklistLock.ExitWriteLock();
}
}
答案 2 :(得分:1)
两个注意事项 - 首先,如果您使用.NET字典的索引器(即System.Collections.Generic.Dictionary)(而不是调用Add()方法):
idList[id] = id;
然后它将添加项目(如果它尚不存在) - 否则,它将替换该键的现有项目。其次,您可以使用ConcurrentDictionary(在System.Collections.Concurrent命名空间中)进行线程安全,因此您不必担心自己锁定。有关使用索引器的相同注释。
答案 3 :(得分:1)
在您的方案中,是的, HashSet是此的最佳选项,因为它包含一个要查找的值,而不像 Dictionary 那需要键和值来执行查找。
当然,正如其他人所说,如果没有被修改,就不需要锁定HashSet。并考虑将其标记为只读。