首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多线程搜索操作

问多线程搜索操作
EN

Stack Overflow用户
提问于 2009-07-19 14:55:41
回答 3查看 7.8K关注 0票数 3

我有一种方法可以使用一系列的查询,我需要针对不同的搜索引擎Web运行它们,比如Google或Yahoo的。为了并行化这个过程,每个查询都会产生一个线程,然后在查询结束时进行join编辑,因为我的应用程序只能在得到每个查询的结果之后才能继续运行。我目前有这样的想法:

代码语言:javascript
复制
public abstract class class Query extends Thread {
    private String query;

    public abstract Result[] querySearchEngine();
    @Override
    public void run() {
        Result[] results = querySearchEngine(query);
        Querier.addResults(results);
    }

}

public class GoogleQuery extends Query {
    public Result querySearchEngine(String query) { 
        // access google rest API
    }
}

public class Querier {
    /* Every class that implements Query fills this array */
    private static ArrayList<Result> aggregatedResults;

    public static void addResults(Result[]) { // add to aggregatedResults }

    public static Result[] queryAll(Query[] queries) {
        /* for each thread, start it, to aggregate results */
        for (Query query : queries) {
            query.start();
        }
        for (Query query : queries) {
            query.join();
        }
        return aggregatedResults;
    }
}

最近,我发现Java中有一个新的API来执行并发工作。即Callable接口、FutureTask和ExecutorService。我想知道这个新的API是否应该使用,以及它们是否比传统的Runnable和Thread更有效。

在研究了这个新API之后,我提出了以下代码(简化版本):

代码语言:javascript
复制
   public abstract class Query implements Callable<Result[]> {
        private final String query; // gets set in the constructor

        public abstract Result[] querySearchEngine();
        @Override
        public Result[] call() {
            return querySearchEngine(query);
        }
    }

public class Querier {   
        private ArrayList<Result> aggregatedResults;

        public Result[] queryAll(Query[] queries) {
            List<Future<Result[]>> futures = new ArrayList<Future<Result[]>>(queries.length);
            final ExecutorService service = Executors.newFixedThreadPool(queries.length);  
            for (Query query : queries) {
                futures.add(service.submit(query));  
            }
            for (Future<Result[]> future : futures) {  
                aggregatedResults.add(future.get());  // get() is somewhat similar to join?
            }  
            return aggregatedResults;
        }
    }

我是这个并发API的新手,我想知道在上面的代码中是否有什么可以改进的,以及它是否比第一个选项(使用Thread)更好。有些类我没有研究过,比如FutureTask,等等。我也想听听关于这方面的任何建议。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-07-19 15:17:38

您的代码有几个问题。

  1. 您可能应该使用ExecutorService.invokeAll()方法。创建新线程和新线程池的成本可能很高(尽管可能与调用外部搜索引擎相比)。invokeAll()可以为您管理线程。
  2. 您可能不想将数组和泛型混合在一起。
  3. 您正在调用aggregatedResults.add()而不是addAll()。
  4. 当成员变量可能是queryAll()函数调用的本地变量时,不需要使用它们。

因此,下面这样的内容应该有效:

代码语言:javascript
复制
public abstract class Query implements Callable<List<Result>> {
    private final String query; // gets set in the constructor

    public abstract List<Result> querySearchEngine();
    @Override
    public List<Result> call() {
        return querySearchEngine(query);
    }
}

public class Querier {   
    private static final ExecutorService executor = Executors.newCachedThreadPool();

    public List<Result> queryAll(List<Query> queries) {
        List<Future<List<Result>>> futures = executor.submitAll(queries);
        List<Result> aggregatedResults = new ArrayList<Result>();
        for (Future<List<Result>> future : futures) {  
            aggregatedResults.addAll(future.get());  // get() is somewhat similar to join?
        }  
        return aggregatedResults;
    }
}
票数 7
EN

Stack Overflow用户

发布于 2009-07-19 15:10:58

作为进一步的改进,您可以考虑使用CompletionService --它解耦提交和检索的顺序,而将所有未来的结果放在一个队列中,从队列中获取结果的完成顺序。

票数 4
EN

Stack Overflow用户

发布于 2009-07-19 16:23:38

我可以建议你使用带有超时的Future.get()吗?

否则,只需要一个搜索引擎没有响应就能使一切停止(如果你的终端有网络问题的话,它甚至不需要成为搜索引擎问题)

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1150073

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档