• 基于用户级线程的远程调用效率测试


    将用户级线程添加到我的工具库中,主要的目的就是用于实现同步远程调用接口。这里的同步,是指在调用返回或超时之前,用户级线程的执行路径

    阻塞在调用接口上,但其底层的线程并不会阻塞,可以继续其它的工作。

    基于这个结构,我的服务器主线程将运行一个用户级线程调度器,并预先创建一组用户级线程池。当收从网络层收到一个网络消息时,从线程池中取出

    一个空闲的线程,将消息交给它处理。这个线程在执行的过程中如果发生了阻塞调用,就将运行权交换给调度器,由调度器挑选下一个可用的线程执行。

    阻塞线程直到超时,或被通知可以解除阻塞才被重新投入到调度器的可运行队列中。

    下面贴出一个简单的测试代码,用于测试调用的效率。

    首先是两个远程函数,一个用于求两数之和,一个用于求两数之积:

    static inline int sum(int32_t arg1,int32_t arg2)
    {
        coro_t co = get_current_coro();
        wpacket_t wpk = wpacket_create(1,wpacket_allocator,64,0);
        wpacket_write_uint32(wpk,(int32_t)co);
        wpacket_write_string(wpk,"sum");
        wpacket_write_uint32(wpk,arg1);
        wpacket_write_uint32(wpk,arg2);
        send_packet(g_channel,wpk);
        //send and block until the response from rpc server
        coro_block(co);
        int ret = rpacket_read_uint32(co->rpc_response);
        rpacket_destroy(&co->rpc_response);
        return ret;
    }
    
    static inline int product(int32_t arg1,int32_t arg2)
    {
        coro_t co = get_current_coro();
        wpacket_t wpk = wpacket_create(1,NULL,64,0);
        wpacket_write_uint32(wpk,(int32_t)co);
        wpacket_write_string(wpk,"product");
        wpacket_write_uint32(wpk,arg1);
        wpacket_write_uint32(wpk,arg2);    
        send_packet(g_channel,wpk);
        //send and block until the response from rpc server
        coro_block(co);
        int ret = rpacket_read_uint32(co->rpc_response);
        rpacket_destroy(&co->rpc_response);
        return ret;
    }

    函数都很简单,将线程id,要求调用的函数名和参数打包并发送给服务器,然后调用coro_block阻塞在上面。当线程重新被唤醒时从应答包中读出返回值

    并从函数返回.

    下面是服务器对这两个远程调用的处理:

    void on_process_packet(struct connection *c,rpacket_t r)
    {
        uint32_t coro_id = rpacket_read_uint32(r);
        const  char *function_name = rpacket_read_string(r);
        int32_t arg1 = rpacket_read_uint32(r);
        int32_t arg2 = rpacket_read_uint32(r);
        uint32_t i = 0;
        wpacket_t w = wpacket_create(0,wpacket_allocator,64,0);
        wpacket_write_uint32(w,coro_id);
        if(strcmp(function_name,"sum") == 0)
            wpacket_write_uint32(w,arg1+arg2);
        else
            wpacket_write_uint32(w,arg1*arg2);
        assert(w);
        connection_send(c,w,NULL);
        rpacket_destroy(&r);
    }

    如代码所示,服务器将调用者的id,函数名和参数取出,执行所要求的计算,然后将计算结果发回给客户端.

    下面再看下客户端的逻辑主循环:

    void *logic_routine(void *arg)
    {
        uint32_t tick = GetSystemMs();
        while(1)
        {
            rpacket_t rpk = peek_msg(g_channel,50);
            if(rpk)
            {
                coro_t co = (coro_t)rpacket_read_uint32(rpk);
                co->rpc_response = rpk;
                coro_wakeup(co);
            }
            uint32_t now = GetSystemMs();
            if(now - tick > 1000)
            {
                printf("call_count:%u\n",call_count);
                tick = now;
                call_count = 0;
            }
            sche_schedule(g_sche);
        }
    }

    主循环不断的尝试从网络层消息队列中获取应答包,接到应答包之后就对应的用户级线程唤醒,然后执行调度器。

    在我的实验环境:一台i5 2.6GZ的双核笔记上,同时运行服务器和客户端,创建25W个用户级线程,平均每秒的远程调用次数大概在90W左右.

    测试程序代码地址:https://github.com/sniperHW/kendylib/tree/master/rpctest

  • 相关阅读:
    杭电acm1517
    杭电acm1228
    杭电acm1859
    杭电acm1124
    杭电acm1327
    CPP Templates 之 template 关键字的用法技巧
    malloc与calloc区别
    CPP Templates 之 类模板的继承
    CPP Templates 之 模板演绎的注意事项
    CPP Templates 之 局部类模板特化
  • 原文地址:https://www.cnblogs.com/sniperHW/p/2705054.html
Copyright © 2020-2023  润新知