libgo & zeromq —— C++下的协程与消息队列的配合

4 篇文章 0 订阅
1 篇文章 0 订阅
本文探讨了libgo通过hook网络阻塞函数实现协程调度时与ZeroMQ的冲突,特别是在ZeroMQ需要原生函数而非hook版本的情况下。文章提供了禁用hook的解决方案,并讨论了使用协程进行非阻塞操作带来的高CPU占用问题,提出了使用线程或ZeroMQ自带模式的替代方案。
摘要由CSDN通过智能技术生成

libgo通过hook了网络阻塞函数来实现协程的调度,但是zeromq只需要原生的函数,如果hook则会报错,Assertion failed: pfd.revents & POLLIN (src/signaler.cpp:261),这时候我们只想要libgo的线程调度功能怎么办?

 只要重新编译一次libgo,把disable_hook打开就可以,如果使用hook版本的,则会出现这个问题。

于是我们重新编译

编译完成后,重新编译一次server & client 即可完成。

服务端

/*
    ZMQ订阅服务器

*/
#include<iostream>
#include<sstream>
#include<zmq.h>

using namespace std;
int main(){
    int port;
    cout<<"请输入你想发布订阅的端口:";
    cin>>port;
    stringstream os;
    os<<"tcp://*:"<<port;

    //开启zmq服务器
    void *ctx=zmq_ctx_new();
    void *publisher=zmq_socket(ctx,ZMQ_PUB);
    int rc=zmq_bind(publisher,os.str().c_str());
    while(1){
        char buffer[10];
        cout<<"发布>>";
        cin>>buffer;
        zmq_send(publisher,buffer,sizeof(buffer),0);
    }
    return 0;
}

客户端 

/*
    ZQM+libgo订阅客户端,可以协程实现对多个服务器的订阅
*/
#include<iostream>
#include<zmq.h>
#include<libgo/coroutine.h>
#include<sstream>

using namespace std;

int main(){
    stringstream os;
    go [&os](){
        int port;
        while(1){
            cout<<"请输入要订阅的服务器端口:";
            cin>>port;
            os.str("");
            os<<"tcp://127.0.0.1:"<<port;
            string addr=os.str();
            go [addr](){        //开启一个新的协程来处理一个服务器的订阅
                void *ctx=zmq_ctx_new();
                void *subscriber=zmq_socket(ctx,ZMQ_SUB);
                int rc=zmq_connect(subscriber,addr.c_str());//连接到服务器
                rc=zmq_setsockopt(subscriber,ZMQ_SUBSCRIBE,":",1);//设定订阅的过滤选项:只订阅那些以:开头的消息
                while(1){
                    char buffer[10];
                    int len=zmq_recv(subscriber,buffer,sizeof(buffer),ZMQ_NOBLOCK); //不阻塞模式
                    if(len==-1){
                        //如果没有收到消息则跳过,因为设置了不阻塞,这样才能方便协程调度
                        co_sleep(1);//睡眠1ms,避免CPU跑飞
                        co_yield;//让出协程
                        continue;
                    }
                    cout<<"收到订阅:"<<buffer<<endl;
                }
            };
        }
    };
    co_sched.Start(2);//开始调度协程,设置为两个调度线程,一个用来调度主要的while输入订阅端口号,一个用来处理各个订阅者
    return 0;
}

最后效果大概是这样

但是这样使用协程强行设置非阻塞和co_sleep的话,CPU其实占用还是很高 

如果在 zmq_recv设置为阻塞,那么阻塞的协程反而会卡住线程,到最后libgo就会自己开一个新的线程去调度协程,那为何不直接用线程做呢? 

所以不是很推荐这样的做法,如果开线程,在线程里面阻塞,或者使用zeromq自带的 Divide and Conquer 模式,可以降低CPU占用,因为zeromq实际上和libgo所hook的网络函数有冲突。

那么 libgo在哪些地方有用呢?我个人感觉是:自己手写网络应用程序的时候,因为只有这个时候才能保证没有错误,否则一些开源的网络库如果这样hook进去的话不保证会成功运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值