线程和列表,我如何遍历每个并进行比较
Threading and List, how do I go through each and compare
我正在尝试使用线程提取嵌套列表以与另一个列表进行比较,类似这样
List<KeyPairValues<string, List<string>> mainList = new List<KeyPairValues<string, List<string>>();
// In my actual code I create these list through a loop
List<string> A = new List<string>();
A.Add("Car");
A.Add("Plain");
A.Add("Boat");
List<string> B = new List<string>();
B.Add("Flower");
B.Add("Dog");
B.Add("House");
List<string> C = new List<string>();
C.Add("Appartment");
C.Add("Plant");
C.Add("Candy");
mainList.Add(new KeyValuePair<string, List<string>>("unRead", A));
mainList.Add(new KeyValuePair<string, List<string>>("unRead", B));
mainList.Add(new KeyValuePair<string, List<string>>("unRead", C));
List<string> compareList = new List<string>();
compareList.Add("Car");
compareList.Add("Boat");
compareList.Add("Dog");
List<string> resList = new List<string>();
我的第一个想法是使用 foreach 循环来遍历它,在我当前的代码中,我在 mainList 中有 32 个列表。
foreach(var item in mainList)
{
if(item.key == "unRead")
{
foreach(var subItem in item.value) // evt do a List<string> temp = item.value first
{
foreach(var compItem in compareList)
{
if(compItem == subItem) resList.Add(compItem);
}
}
item.remove(); // I actualy wanted to change from unRead to read, but I figured I could just remove it from the list.
}
}
如果我使用 Threads 并在单独的线程中遍历每个列表,evt 的最大线程数量为 10 左右,这应该会更快。
所以我尝试的是这样做。
foreach(var item in mainList)
{
Thread myThread = new Thread(() =>
{
if(item.key == "unRead")
{
foreach(var subItem in item.value) // evt do a List<string> temp = item.value first
{
foreach(var compItem in compareList)
{
if(compItem == subItem) resList.Add(compItem);
}
}
item.remove(); // I actualy wanted to change from unRead to read, but I figured I could just remove it from the list.
}
});
myThread.start();
}
但这根本没有给出任何预期的输出...
那我做错了什么?
resList
应该加锁,因为是在多线程修改的。您还需要等到所有线程都完成。您应该为此使用 Parallel.Foreach()
。
例如:
Parallel.Foreach(mainList, (item) =>
{
if(item.key == "unRead")
{
foreach(var subItem in item.value) // evt do a List<string> temp = item.value first
{
foreach(var compItem in compareList)
{
if(compItem == subItem)
lock(resList)
resList.Add(compItem);
}
}
}
});
mainList.RemoveAll(item => item.key == "unRead");
这可以用一些 linq-magic 来缩短:
Parallel.Foreach(mainList, (item) =>
{
if(item.key == "unRead")
{
foreach(var subItem in item.value) // evt do a List<string> temp = item.value first
{
if(compareList.Contains(subItem))
lock(resList)
resList.Add(compItem);
}
}
});
没有threading/locking:
var resList = mainList.Where(item => item.key == "unRead")
.SelectMany(subitem => compareList.Contains(subitem))).ToList();
对于 compareList
使用 HashSet<>
而不是 List<>
会很有用
正如 Jerone van Langen 所指出的,问题是对列表的访问导致了竞争条件。您可以通过引入锁来解决这个问题,也可以使用线程安全的集合实现。后一种方法包括无锁工作的 类,这可能会给您带来更好的性能结果。例如,您可以查看 System.Collections.Concurrent.ConcurrentBag
.
无论哪种方式,第一个优化肯定是对比较列表使用哈希集,至少如果您希望这些列表包含超过 10 个元素(否则,列表可能更快)。
我正在尝试使用线程提取嵌套列表以与另一个列表进行比较,类似这样
List<KeyPairValues<string, List<string>> mainList = new List<KeyPairValues<string, List<string>>();
// In my actual code I create these list through a loop
List<string> A = new List<string>();
A.Add("Car");
A.Add("Plain");
A.Add("Boat");
List<string> B = new List<string>();
B.Add("Flower");
B.Add("Dog");
B.Add("House");
List<string> C = new List<string>();
C.Add("Appartment");
C.Add("Plant");
C.Add("Candy");
mainList.Add(new KeyValuePair<string, List<string>>("unRead", A));
mainList.Add(new KeyValuePair<string, List<string>>("unRead", B));
mainList.Add(new KeyValuePair<string, List<string>>("unRead", C));
List<string> compareList = new List<string>();
compareList.Add("Car");
compareList.Add("Boat");
compareList.Add("Dog");
List<string> resList = new List<string>();
我的第一个想法是使用 foreach 循环来遍历它,在我当前的代码中,我在 mainList 中有 32 个列表。
foreach(var item in mainList)
{
if(item.key == "unRead")
{
foreach(var subItem in item.value) // evt do a List<string> temp = item.value first
{
foreach(var compItem in compareList)
{
if(compItem == subItem) resList.Add(compItem);
}
}
item.remove(); // I actualy wanted to change from unRead to read, but I figured I could just remove it from the list.
}
}
如果我使用 Threads 并在单独的线程中遍历每个列表,evt 的最大线程数量为 10 左右,这应该会更快。 所以我尝试的是这样做。
foreach(var item in mainList)
{
Thread myThread = new Thread(() =>
{
if(item.key == "unRead")
{
foreach(var subItem in item.value) // evt do a List<string> temp = item.value first
{
foreach(var compItem in compareList)
{
if(compItem == subItem) resList.Add(compItem);
}
}
item.remove(); // I actualy wanted to change from unRead to read, but I figured I could just remove it from the list.
}
});
myThread.start();
}
但这根本没有给出任何预期的输出...
那我做错了什么?
resList
应该加锁,因为是在多线程修改的。您还需要等到所有线程都完成。您应该为此使用 Parallel.Foreach()
。
例如:
Parallel.Foreach(mainList, (item) =>
{
if(item.key == "unRead")
{
foreach(var subItem in item.value) // evt do a List<string> temp = item.value first
{
foreach(var compItem in compareList)
{
if(compItem == subItem)
lock(resList)
resList.Add(compItem);
}
}
}
});
mainList.RemoveAll(item => item.key == "unRead");
这可以用一些 linq-magic 来缩短:
Parallel.Foreach(mainList, (item) =>
{
if(item.key == "unRead")
{
foreach(var subItem in item.value) // evt do a List<string> temp = item.value first
{
if(compareList.Contains(subItem))
lock(resList)
resList.Add(compItem);
}
}
});
没有threading/locking:
var resList = mainList.Where(item => item.key == "unRead")
.SelectMany(subitem => compareList.Contains(subitem))).ToList();
对于 compareList
HashSet<>
而不是 List<>
会很有用
正如 Jerone van Langen 所指出的,问题是对列表的访问导致了竞争条件。您可以通过引入锁来解决这个问题,也可以使用线程安全的集合实现。后一种方法包括无锁工作的 类,这可能会给您带来更好的性能结果。例如,您可以查看 System.Collections.Concurrent.ConcurrentBag
.
无论哪种方式,第一个优化肯定是对比较列表使用哈希集,至少如果您希望这些列表包含超过 10 个元素(否则,列表可能更快)。