我有一个名为List<String>
的{{1}}和一个名为lines
的巨型(~3G)Set<String>
。我需要找到位于voc
的{{1}}中的所有行。我可以这样做多线程吗?
目前我有这个简单的代码:
lines
有没有办法同时搜索几行?可能有现成的解决方案吗?
PS:我正在使用voc
,因为它在填充期间表现更好。
答案 0 :(得分:2)
这是一个可能的实现。请注意,错误/中断处理已被省略,但这可能会给您一个起点。我包含了一个main方法,因此您可以将其复制并粘贴到IDE中以进行快速演示。
修改:为了提高可读性和列表分区而稍微清理了一下
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ParallelizeListSearch {
public static void main(String[] args) throws InterruptedException, ExecutionException {
List<String> searchList = new ArrayList<String>(7);
searchList.add("hello");
searchList.add("world");
searchList.add("java");
searchList.add("debian");
searchList.add("linux");
searchList.add("jsr-166");
searchList.add("stack");
Set<String> targetSet = new HashSet<String>(searchList);
Set<String> matchSet = findMatches(searchList, targetSet);
System.out.println("Found " + matchSet.size() + " matches");
for(String match : matchSet){
System.out.println("match: " + match);
}
}
public static Set<String> findMatches(List<String> searchList, Set<String> targetSet) throws InterruptedException, ExecutionException {
Set<String> locatedMatchSet = new HashSet<String>();
int threadCount = Runtime.getRuntime().availableProcessors();
List<List<String>> partitionList = getChunkList(searchList, threadCount);
if(partitionList.size() == 1){
//if we only have one "chunk" then don't bother with a thread-pool
locatedMatchSet = new ListSearcher(searchList, targetSet).call();
}else{
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
CompletionService<Set<String>> completionService = new ExecutorCompletionService<Set<String>>(executor);
for(List<String> chunkList : partitionList)
completionService.submit(new ListSearcher(chunkList, targetSet));
for(int x = 0; x < partitionList.size(); x++){
Set<String> threadMatchSet = completionService.take().get();
locatedMatchSet.addAll(threadMatchSet);
}
executor.shutdown();
}
return locatedMatchSet;
}
private static class ListSearcher implements Callable<Set<String>> {
private final List<String> searchList;
private final Set<String> targetSet;
private final Set<String> matchSet = new HashSet<String>();
public ListSearcher(List<String> searchList, Set<String> targetSet) {
this.searchList = searchList;
this.targetSet = targetSet;
}
@Override
public Set<String> call() {
for(String searchValue : searchList){
if(targetSet.contains(searchValue))
matchSet.add(searchValue);
}
return matchSet;
}
}
private static <T> List<List<T>> getChunkList(List<T> unpartitionedList, int splitCount) {
int totalProblemSize = unpartitionedList.size();
int chunkSize = (int) Math.ceil((double) totalProblemSize / splitCount);
List<List<T>> chunkList = new ArrayList<List<T>>(splitCount);
int offset = 0;
int limit = 0;
for(int x = 0; x < splitCount; x++){
limit = offset + chunkSize;
if(limit > totalProblemSize)
limit = totalProblemSize;
List<T> subList = unpartitionedList.subList(offset, limit);
chunkList.add(subList);
offset = limit;
}
return chunkList;
}
}
答案 1 :(得分:1)
绝对可以使用多个线程并行化。您可以执行以下操作:
例如,您可能有以下线程例程:
public void scanAndAdd(List<String> allStrings, Set<String> toCheck,
ConcurrentSet<String> matches, int start, int end) {
for (int i = start; i < end; i++) {
if (toCheck.contains(allStrings.get(i))) {
matches.add(allStrings.get(i));
}
}
}
然后,您可以生成所需数量的线程,以运行上述方法并等待所有线程完成。然后,生成的匹配将存储在matches
。
为简单起见,我的输出设置为ConcurrentSet
,它会自动消除由于写入引起的竞争条件。由于您只对要检查的字符串和字符串列表进行读取,因此从allStrings
读取或在toCheck
中执行查找时不需要同步。
希望这有帮助!
答案 2 :(得分:1)
如果您正在寻找此功能,只需在不同的线程之间拆分行(至少在Oracle JVM中)将工作分散到所有CPU中。 我喜欢使用CyclicBarrier,让这些线程更容易控制。
http://javarevisited.blogspot.cz/2012/07/cyclicbarrier-example-java-5-concurrency-tutorial.html
答案 3 :(得分:0)
另一种选择是使用Akka,它可以非常简单地完成这些事情。
实际上,在与Akka进行了一些搜索工作之后,我可以告诉你的一件事就是它支持两种并行化方式:通过Composable Futures或Agents。对于您想要的,可组合期货将是完全足够的。然后,Akka实际上并没有增加那么多:Netty正在提供大规模并行的io基础设施,而Futures是jdk的一部分,但Akka确实将这两者放在一起并在需要时扩展它们非常简单。