Asynchronous example Thrift in Java

4 篇文章 0 订阅
2 篇文章 0 订阅

Asynchronous example Thrift in Java

上一篇试了下同步的例子,这篇来玩玩异步调用是怎样滴~直接上代码~

1. 例子代码:

异步调用的服务端:
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.server.TNonblockingServer;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;
import tutorial.MultiplicationService;
import tutorial.MultiplicationServiceImpl;

public class AsyncServer {

    public static final int SERVER_PORT = 8090;

    public static final int CLIENT_TIMEOUT = 30000;

    public void startServer() {
        try {
            System.out.println("AsyncServer start ....");

            TProcessor tprocessor = new MultiplicationService.Processor(new MultiplicationServiceImpl());
            TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(SERVER_PORT, CLIENT_TIMEOUT);
            TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args(tnbSocketTransport);
            tnbArgs.processor(tprocessor);
            tnbArgs.transportFactory(new TFramedTransport.Factory());
            tnbArgs.protocolFactory(new TCompactProtocol.Factory());

            // 使用非阻塞式IO,服务端和客户端需要指定TFramedTransport数据传输的方式
            TServer server = new TNonblockingServer(tnbArgs);
            server.serve();

        } catch (Exception e) {
            System.out.println("Server start error!!!");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        AsyncServer server = new AsyncServer();
        server.startServer();
    }
}
异步调用的客户端:
import org.apache.thrift.TException;
import org.apache.thrift.async.AsyncMethodCallback;
import org.apache.thrift.async.TAsyncClientManager;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.transport.TNonblockingSocket;
import org.apache.thrift.transport.TNonblockingTransport;
import tutorial.MultiplicationService;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class AsynClient {

    public static final String SERVER_IP = "localhost";
    public static final int SERVER_PORT = 8090;
    public static final int TIMEOUT = 30;
    public static final int THREAD_NUM = 8;

    public void startClient() {
        try {
            System.out.println("Client start .....");
            CountDownLatch latch = new CountDownLatch(THREAD_NUM);

            // We only need one protocol factory
            TProtocolFactory tprotocol = new TCompactProtocol.Factory();

            long start = System.currentTimeMillis();
            for (int i = 0; i < THREAD_NUM; i++) {
                TNonblockingTransport transport = new TNonblockingSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
                MultiplicationService.AsyncClient asyncClient = new MultiplicationService.AsyncClient(tprotocol,
                        new TAsyncClientManager(), transport);
                new Thread(new AsynSendTask(asyncClient, new AsynCallback(latch))).start();
            }

            latch.await(300, TimeUnit.SECONDS);
            long elapsedTime = System.currentTimeMillis() - start;

            System.out.println("elapsed time is (s): " + elapsedTime / 1000);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("startClient end.");
    }

    public class AsynSendTask implements Runnable {

        private MultiplicationService.AsyncClient asyncClient;
        private AsynCallback callBack;

        public AsynSendTask(MultiplicationService.AsyncClient asyncClient, AsynCallback callBack) {
            this.asyncClient = asyncClient;
            this.callBack = callBack;
        }

        @Override
        public void run() {
            try {
                //for (int i = 0; i < 10; i++) {
                    asyncClient.multiply(2, 3, callBack);
                //}
            } catch (TException e) {
                e.printStackTrace();
            }
        }
    }

    public class AsynCallback implements AsyncMethodCallback<MultiplicationService.AsyncClient.multiply_call> {
        private CountDownLatch latch;

        public AsynCallback(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void onComplete(MultiplicationService.AsyncClient.multiply_call response) {
            System.out.println("onComplete");
            try {
                //TimeUnit.SECONDS.sleep(10);
                System.out.println("AsynCall result =:" + response.getResult());
            } catch (TException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                latch.countDown();
            }
        }

        @Override
        public void onError(Exception exception) {
            System.out.println("onError :" + exception.getMessage());
            latch.countDown();
        }
    }

    public static void main(String[] args) {
        AsynClient client = new AsynClient();
        client.startClient();
    }
}

从上面代码可以发现有两个值得关注的问题:

1. for (int i = 0; i < THREAD_NUM; i++) {} 这里面,每个循环都得新构造一个TNonblockingSocket,新构造一个AsyncClient。尝试过每个线程都只使用一个socket与client,表示公用一条链路,会抛出异常:java.lang.IllegalStateException: Client is currently executing another method: tutorial.MultiplicationService AsyncClient multiply_call

由此可知调用时只能一条请求线程使用一条链路..

2. 为了测试异步,将代码修改下,对于同个client调用多次看看结果:
for (int i = 0; i < n; i++) {
    asyncClient.multiply(2, 3, callBack);
}

然后却是抛出跟上面同样的异常,说好的异步呢?我哪里认知错了?按我的理解同一个线程client应该可以调用多次,调用的结果异步通过callback可取。


2. 封装给多线程调用

例子从Stack Overflow中一个回答改造而来,给大家参考下,服务端代码还是以上的,客户代码改造如下:~

import org.apache.thrift.async.TAsyncClientManager;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.transport.TNonblockingSocket;
import tutorial.MultiplicationService.AsyncClient;
import tutorial.MultiplicationService.AsyncClient.Factory;

import java.io.IOException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;

public class Thrift {

    // This is the request
    public static abstract class ThriftRequest {

        private void go(final Thrift thrift, final AsyncClient cli) {
            on(cli);
            thrift.ret(cli);
        }

        public abstract void on(AsyncClient cli);
    }

    // Holds all of our Async Clients
    private final ConcurrentLinkedQueue<AsyncClient> instances = new ConcurrentLinkedQueue<AsyncClient>();
    // Holds all of our postponed requests
    private final ConcurrentLinkedQueue<ThriftRequest> requests = new ConcurrentLinkedQueue<ThriftRequest>();
    // Holds our executor, if any
    private Executor exe = null;

    /**
     * This factory runs in thread bounce mode, meaning that if you call it from
     * many threads, execution bounces between calling threads depending on when
     * execution is needed.
     */
    public Thrift(
            final int clients,
            final int clients_per_message_processing_thread,
            final String host,
            final int port) throws IOException {

        // We only need one protocol factory
        TProtocolFactory proto_fac = new TCompactProtocol.Factory();

        // Create our clients
        Factory fac = null;
        for (int i = 0; i < clients; i++) {

            if (fac == null || i % clients_per_message_processing_thread == 0) {
                fac = new AsyncClient.Factory(new TAsyncClientManager(), proto_fac);
            }

            instances.add(fac.getAsyncClient(new TNonblockingSocket(host, port)));
        }
    }

    /**
     * This factory runs callbacks in whatever mode the executor is setup for,
     * not on calling threads.
     */
    public Thrift(Executor exe,
                  final int clients,
                  final int clients_per_message_processing_thread,
                  final String host,
                  final int port) throws IOException {
        this(clients, clients_per_message_processing_thread, host, port);
        this.exe = exe;
    }

    // Call this to grab an instance
    public void req(final ThriftRequest req) {
        final AsyncClient cli;
        synchronized (instances) {
            cli = instances.poll();
        }
        if (cli != null) {
            if (exe != null) {
                // Executor mode
                exe.execute(new Runnable() {

                    @Override
                    public void run() {
                        req.go(Thrift.this, cli);
                    }

                });
            } else {
                // Thread bounce mode
                req.go(this, cli);
            }
            return;
        }
        // No clients immediately available
        requests.add(req);
    }

    private void ret(final AsyncClient cli) {
        final ThriftRequest req;
        synchronized (requests) {
            req = requests.poll();
        }
        if (req != null) {
            if (exe != null) {
                // Executor mode
                exe.execute(new Runnable() {

                    @Override
                    public void run() {
                        req.go(Thrift.this, cli);
                    }
                });
            } else {
                // Thread bounce mode
                req.go(this, cli);
            }
            return;
        }
        // We did not need this immediately, hold onto it
        instances.add(cli);
    }
}

调用的代码:

import org.apache.thrift.TException;
import org.apache.thrift.async.AsyncMethodCallback;
import tutorial.MultiplicationService.AsyncClient;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class Client {

    public static final int THREAD_NUM = 8;
    private static final CountDownLatch latch = new CountDownLatch(THREAD_NUM);

    public static void main(String[] args) throws IOException, InterruptedException {

        // Make the pool
        Thrift t = new Thrift(THREAD_NUM, THREAD_NUM, "localhost", 8090);

        long start = System.currentTimeMillis();
        for (int i = 0; i < THREAD_NUM; i++) {
            t.req(new MyThriftRequest());// Use the pool
        }

        latch.await(60, TimeUnit.SECONDS);
        long elapsedTime = System.currentTimeMillis() - start;
        System.out.println("elapsed time is (s): " + elapsedTime / 1000);
    }

    static class MyThriftRequest extends Thrift.ThriftRequest {

        @Override
        public void on(AsyncClient cli) {
            try {
                cli.multiply(2, 5, new AsyncMethodCallback<AsyncClient.multiply_call>() {

                    @Override
                    public void onComplete(AsyncClient.multiply_call response) {
                        try {
                            System.out.println("AsynCall result =:" + response.getResult());
                        } catch (TException e) {
                            e.printStackTrace();
                        } finally {
                            latch.countDown();
                        }
                    }

                    @Override
                    public void onError(Exception e) {
                        System.out.println("onError :" + e.getMessage());
                        latch.countDown();
                    }
                });
            } catch (TException e) {
                e.printStackTrace();
            }
        }
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值