java / python异步请求接口的实现

134 阅读2分钟

python发送异步请求

在 Python 中,使用asyncio异步框架可以实现异步任务的调度和执行,选择使用httpx来发送异步的请求。异步和同步请求方式的对比:

# 异步请求
async def async_send_request():
    async with httpx.AsyncClient() as client:
        response = await client.request("GET", url)
    return response.text
 
async def async_main():
    start_time = time.time()
    tasks = [async_send_request() for i in range(100)]
    results = await asyncio.gather(*tasks)
    end_time = time.time()
    print(f"程序耗时:{int((end_time - start_time) * 1000)}")
 
# 同步请求
def send_request():
    with httpx.Client() as client:
        response = client.request("GET", url)
    return response.text
 
def main():
    start_time = time.time()
    results = [send_request() for i in range(100)]
    end_time = time.time()
    print(f"程序耗时:{int((end_time - start_time) * 1000)}")

异步和同步请求耗时的对比:

if __name__ == '__main__':
    asyncio.run(async_main())
    main()
 
程序耗时:1161
程序耗时:10558

java发送异步请求

Java异步可以通过多种方式实现,这里选择CompletableFuture异步框架,请求方式使用HttpClient。也可以使用HttpAsyncClient发送异步请求,需传入FutureCallback接口实现类参数来进行异步的回调,请求返回的是一个Future对象。异步请求的实现如下:

    // 同步发送请求
    public static void run() throws IOException {
        long startTime = System.currentTimeMillis();
        CloseableHttpClient httpclient = HttpClients.createDefault();
        for (int i = 0; i < 10; i++) {
            try {
                sendRequest(url, httpclient);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("程序耗时:" + (endTime - startTime));
        httpclient.close();
    }
    // 异步发送请求
    public static void runAsync() throws IOException {
        long startTime = System.currentTimeMillis();
        CloseableHttpClient httpclient = HttpClients.createDefault();
        List<CompletableFuture<String>> futures = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                try {
                    return sendRequest(url, httpclient);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
            futures.add(future);
        }
        CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        allOf.join();  // 等待所有异步操作完成
        long endTime = System.currentTimeMillis();
        System.out.println("程序耗时:" + (endTime - startTime));
        httpclient.close();
    }
    // 使用HttpAsyncClient方式,异步发送请求
    public static void runAsyncClient() throws IOException, InterruptedException {
        long startTime = System.currentTimeMillis();
        CloseableHttpAsyncClient httpAsyncClient = HttpAsyncClients.custom().build();
        httpAsyncClient.start();
        HttpGet request = new HttpGet(url);
        MyCallback myCallback = new MyCallback();
        for (int i = 0; i < 10; i++) {
            httpAsyncClient.execute(request, myCallback);
        }
        Thread.sleep(1500);  // 等待所有异步操作完成
        long endTime = myCallback.responseTime;
        System.out.println("程序耗时:" + (endTime - startTime));
        httpAsyncClient.close();
    }
 
    public static String sendRequest(String url, CloseableHttpClient httpclient) throws IOException {
        HttpGet request = new HttpGet(url);
        HttpResponse response = httpclient.execute(request);
        return EntityUtils.toString(response.getEntity()) ;
    }
 
    private static final class MyCallback implements FutureCallback<HttpResponse> {
        public long responseTime;
        @Override
        public void completed(HttpResponse httpResponse) {
            responseTime = Math.max(System.currentTimeMillis(), responseTime);
        }
        @Override
        public void failed(Exception e) {
            e.printStackTrace();
        }
        @Override
        public void cancelled() {
        }
    }

异步和同步发送请求的对比:

public static void main(String[] args) throws IOException, InterruptedException {
        runAsync();
        run();
        runAsyncClient();
}
 
程序耗时:1253
程序耗时:7486
程序耗时:1053

总结 

当程序需要多频次地访问请求时,可以使用异步请求的方式解决网络IO造成的阻塞等待,使程序达到最佳地执行效率。