Linkedin parseq。一个接一个的任务如何运行?

时间:2019-07-08 08:29:06

标签: java asynchronous java-8 linkedin

我正在使用parseq框架进行异步计算。

请考虑以下代码。它首先查询google.com的内容,然后将内容映射到其长度。最后,打印出长度。

问题是仅第一个任务运行。为什么?

public class Main {

    public static void main(String[] args) throws Exception {

        OkHttpClient okHttpClient = new OkHttpClient();

        final int numCores = Runtime.getRuntime().availableProcessors();
        final ExecutorService taskScheduler = Executors.newFixedThreadPool(numCores + 1);
        final ScheduledExecutorService timerScheduler = Executors.newScheduledThreadPool(numCores + 1);

        final Engine engine = new EngineBuilder()
                .setTaskExecutor(taskScheduler)
                .setTimerScheduler(timerScheduler)
                .build();

        Task<Integer> task = Task.async(() -> {
            SettablePromise<String> promise = Promises.settable();

            Request request = new Request.Builder()
                    .url("http://google.com")
                    .build();

            okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    System.out.println("error");
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    promise.done(response.body().string());
                }
            });

            return promise;

        }).map("map content to length", content -> content.length())
                .andThen(System.out::println);

        engine.blockingRun(task);
        engine.blockingRun(task);
    }
}

2 个答案:

答案 0 :(得分:1)

通过使用HttpClient而不是OkHttp可以解决您的问题。

以下是我用于此代码的总体Maven依赖项:

<dependency>
    <groupId>com.linkedin.parseq</groupId>
    <artifactId>parseq</artifactId>
    <version>3.0.11</version>
</dependency>
<dependency>
    <groupId>com.linkedin.parseq</groupId>
    <artifactId>parseq-http-client</artifactId>
    <version>3.0.11</version>
</dependency>

import com.linkedin.parseq.Engine;
import com.linkedin.parseq.EngineBuilder;
import com.linkedin.parseq.Task;
import com.linkedin.parseq.httpclient.HttpClient;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

public class Main  {
    private static Task<Integer> fetchBody(String url) {
        Task<Integer> map = HttpClient.get(url).task().map("map content to length", content -> content.getResponseBody().length());
        return map;
    }

    public static void main(String[] args) {
        final int numCores = Runtime.getRuntime().availableProcessors();
        final ExecutorService taskScheduler = Executors.newFixedThreadPool(numCores + 1);
        final ScheduledExecutorService timerScheduler = Executors.newScheduledThreadPool(numCores + 1);
        final Engine engine = new EngineBuilder()
                .setTaskExecutor(taskScheduler)
                .setTimerScheduler(timerScheduler)
                .build();
        final Task<Integer> stackOverFlow = fetchBody("http://www.stackoverflow.com");
        final Task<Integer> google = fetchBody("http://www.google.com");
        final Task<Integer> ethereum = fetchBody("http://ethereum.stackexchange.com");
        final Task<String> plan = Task.par(stackOverFlow, google, ethereum)
                .map((s, g, e) -> "StackOverFlow Page: " + s + " \n" +
                        "Google Page: " + g + "\n" +
                        "Ethereum Page: " + e + "\n")
                .andThen(System.out::println);
        engine.run(plan);
    }
}

输出:

StackOverFlow Page: 149 
Google Page: 13097
Ethereum Page: 152
  

此示例是完全异步的。 StackOverflow的主页,   谷歌和以太坊都是并行获取的,而原始   线程已返回到调用代码。我们使用Tasks.par告诉   引擎以并行化这些HTTP请求。一旦所有回应   已被检索到,它们被转换为int(字符串   长度),最后打印出来。

要点https://gist.github.com/vishwaratna/26417f7467a4e827eadeee6923ddf3ae

答案 1 :(得分:1)

因为你使用相同的任务来运行。

Task 是 interface ,抽象类是 BaseTask ,包含字段“_stateRef”,该字段维护任务状态。

首先在INIT状态下运行任务,当第一次执行时。状态更改为 RUN。 在此代码中阻止任务执行。 com.linkedin.parseq.BaseTask#contextRun

有一个判断:transitionRun(traceBuilder)

所以,正确的代码执行方式如下:

 private void replayOkHttpNotExecuteSecondTask() {
    try {
        log.info("begin task");
        engine.blockingRun(okHttpTask());
        engine.blockingRun(okHttpTask());


    } catch (Exception e) {
        e.printStackTrace();
    }
}


private Task okHttpTask() {
    OkHttpClient okHttpClient = new OkHttpClient();
    return Task.async(() -> {
        SettablePromise<String> settablePromise = Promises.settable();
        Request request = new Request.Builder().url("http://baidu.com").build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println("error");
            }

            @Override
            public void onResponse(Call call, okhttp3.Response response) throws IOException {
                settablePromise.done(response.body().string());
            }
        });
        return settablePromise;
    }).map("map to length", content -> content.length())
            .andThen(System.out::println);
}