Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/375.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
如何在java中以最高效、最优雅的方式使用并行处理_Java_Java 8_Parallel Processing_Java Stream - Fatal编程技术网

如何在java中以最高效、最优雅的方式使用并行处理

如何在java中以最高效、最优雅的方式使用并行处理,java,java-8,parallel-processing,java-stream,Java,Java 8,Parallel Processing,Java Stream,我想并行请求不同的数据源(因为每个请求都是http调用,可能非常耗时)。但我将只使用这些请求的一个响应。所以我会优先考虑它们。如果第一个响应无效,我将检查第二个响应。如果它也是无效的,我想用第三个,等等。 但我希望在收到第一个正确响应后立即停止处理并返回结果 为了模拟这个问题,我创建了以下代码,其中我尝试使用java并行流。但问题是,我只有在处理完所有请求后才能收到最终结果 public class ParallelExecution { private static Supplier

我想并行请求不同的数据源(因为每个请求都是http调用,可能非常耗时)。但我将只使用这些请求的一个响应。所以我会优先考虑它们。如果第一个响应无效,我将检查第二个响应。如果它也是无效的,我想用第三个,等等。 但我希望在收到第一个正确响应后立即停止处理并返回结果

为了模拟这个问题,我创建了以下代码,其中我尝试使用java并行流。但问题是,我只有在处理完所有请求后才能收到最终结果

public class ParallelExecution {

    private static Supplier<Optional<Integer>> testMethod(String strInt) {
        return () -> {
            Optional<Integer> result = Optional.empty();
            try {
                result = Optional.of(Integer.valueOf(strInt));
                System.out.printf("converted string %s to int %d\n",
                        strInt,
                        result.orElse(null));
            } catch (NumberFormatException ex) {
                System.out.printf("CANNOT CONVERT %s to int\n", strInt);
            }

            try {
                int randomValue = result.orElse(10000);
                TimeUnit.MILLISECONDS.sleep(randomValue);
                System.out.printf("converted string %s to int %d in %d milliseconds\n",
                        strInt,
                        result.orElse(null), randomValue);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result;
        };
    }

    public static void main(String[] args) {
        Instant start = Instant.now();
        System.out.println("Starting program: " + start.toString());
        List<Supplier<Optional<Integer>>> listOfFunctions = new ArrayList();
        for (String arg: args) {
            listOfFunctions.add(testMethod(arg));
        }
        Integer value = listOfFunctions.parallelStream()
                .map(function -> function.get())
                .filter(optValue -> optValue.isPresent()).map(val-> {
                    System.out.println("************** VAL: " + val);
                    return val;
                }).findFirst().orElse(null).get();
        Instant end = Instant.now();
        Long diff = end.toEpochMilli() - start.toEpochMilli();
        System.out.println("final value:" + value + ", worked during " + diff + "ms");
    }
}
我想尽快得到结果“34”(大约在34毫秒后),但事实上,我已经等了10秒多了


您能否帮助找到此问题的最有效解决方案?

您可以使用队列将结果放入:

private static void testMethod(String strInt, BlockingQueue<Integer> queue) {
    // your code, but instead of returning anything:
    result.ifPresent(queue::add);
}
请注意,这将只处理第一个结果,就像在您的示例中一样。

看起来是一个不错的选择

List<Callable<Optional<Integer>>> tasks = listOfFunctions
    .stream()
    .<Callable<Optional<Integer>>>map(f -> f::get)
    .collect(Collectors.toList());

ExecutorService service = Executors.newCachedThreadPool();
Optional<Integer> value = service.invokeAny(tasks);

service.shutdown();

我用competableFutures和anyOf方法尝试过。它将在未来的任何一个任务完成时返回。现在,停止其他任务的关键是为可完成的未来提供您自己的executor服务,并在需要时将其关闭

  public static void main(String[] args) {
    Instant start = Instant.now();
    System.out.println("Starting program: " + start.toString());
    CompletableFuture<Optional<Integer>> completableFutures[] = new CompletableFuture[args.length];
    ExecutorService es = Executors.newFixedThreadPool(args.length,r -> {
            Thread t = new Thread(r);
            t.setDaemon(false);
            return t;
    });

    for (int i = 0;i < args.length; i++) {
        completableFutures[i] = CompletableFuture.supplyAsync(testMethod(args[i]),es);
    }
    CompletableFuture.anyOf(completableFutures).
            thenAccept(res-> {
                System.out.println("Result - " + res + ", Time Taken : " + (Instant.now().toEpochMilli()-start.toEpochMilli()));
                es.shutdownNow();
            });
}
publicstaticvoidmain(字符串[]args){
即时开始=即时。现在();
System.out.println(“启动程序:+start.toString());
CompletableFuture completableFutures[]=新的CompletableFuture[args.length];
ExecutorService es=Executors.newFixedThreadPool(args.length,r->{
螺纹t=新螺纹(r);
t、 setDaemon(false);
返回t;
});
对于(int i=0;i{
System.out.println(“结果-”+res+“,所用时间:”+(Instant.now().toEpochMilli()-start.toEpochMilli());
es.shutdownNow();
});
}

PS:它将引发中断的异常,您可以在try-catch块中忽略这些异常,而不打印堆栈跟踪。此外,理想情况下,您的线程池大小应该与args数组的长度相同。

如果我理解的话,
ExecutorCompletionService
链接到
ExecutorService
,并允许我们使用
take
,结果一结束就得到,不管顺序如何?我使用了
列表
(使用调用顺序,不太好)或回调方法(verbose)来完成这类工作。@AxelH是的,顺序与
take()
无关,但是
invokeAny
在第一个任务返回空的
可选
时就可以了。首先创建
可调用的
s,而不是必须包装的
供应商,这将更有意义。然后,异常应该简单地传播到调用方,而不是转换为空选项。@Holger是的,我考虑过了。最好传播一个
NumberFormatException
,而不是捕获它并返回一个空的可选值。
List<Callable<Optional<Integer>>> tasks = listOfFunctions
    .stream()
    .<Callable<Optional<Integer>>>map(f -> f::get)
    .collect(Collectors.toList());

ExecutorService service = Executors.newCachedThreadPool();
Optional<Integer> value = service.invokeAny(tasks);

service.shutdown();
List<Callable<Optional<Integer>>> tasks = Arrays
    .stream(args)
    .<Callable<Optional<Integer>>>map(arg -> () -> testMethod(arg).get())
    .collect(Collectors.toList());

final ExecutorService underlyingService = Executors.newCachedThreadPool();
final ExecutorCompletionService<Optional<Integer>> service = new ExecutorCompletionService<>(underlyingService);
tasks.forEach(service::submit);

Optional<Integer> value = service.take().get();
underlyingService.shutdownNow();
  public static void main(String[] args) {
    Instant start = Instant.now();
    System.out.println("Starting program: " + start.toString());
    CompletableFuture<Optional<Integer>> completableFutures[] = new CompletableFuture[args.length];
    ExecutorService es = Executors.newFixedThreadPool(args.length,r -> {
            Thread t = new Thread(r);
            t.setDaemon(false);
            return t;
    });

    for (int i = 0;i < args.length; i++) {
        completableFutures[i] = CompletableFuture.supplyAsync(testMethod(args[i]),es);
    }
    CompletableFuture.anyOf(completableFutures).
            thenAccept(res-> {
                System.out.println("Result - " + res + ", Time Taken : " + (Instant.now().toEpochMilli()-start.toEpochMilli()));
                es.shutdownNow();
            });
}