C++和Python 使用zmq的push和pull将任务下发给多个worker进程

示例仓库代码: https://gitee.com/liudegui/batch_tasks_to_workers_via_zmq

zeroMQ在设计上主要采用了以下几个高性能的特征

1、无锁的队列模型

对于跨线程间的交互(用户端和session)之间的数据交换通道pipe,采用无锁的队列算法CAS;在pipe的两端注册有异步事件,在读或者写消息到pipe的时,会自动触发读写事件。

2、批量处理的算法

对于传统的消息处理,每个消息在发送和接收的时候,都需要系统的调用,这样对于大量的消息,系统的开销比较大,zeroMQ对于批量的消息,进行了适应性的优化,可以批量的接收和发送消息。

3、多核下的线程绑定,无须CPU切换

区别于传统的多线程并发模式,信号量或者临界区, zeroMQ充分利用多核的优势,每个核绑定运行一个工作者线程,避免多线程之间的CPU切换开销。

4、进程内通信zmq_inproc – ØMQ 本地进程内(线程间)传输方式

当你的程序只使用inproc作为通讯手段的时候, 其实是不需要线程来处理异步I/O的, 因为inproc是通过共享内存实现通讯的. 这个时候你可以手动设置I/O线程的数量为0. 这是一个小小的优化手段, 嗯, 对性能的提升基本为0.

5、进程间通信zmq_ipc – ZMQ本地进程间通信传输协议

进程间传输采用与系统相关的IPC机制进行本地进程间的消息通信。
进程间传输方式目前只在提供UNIX定义的socket系统上完全的实现

C++发布任务进程

//
//  Task ventilator in C++
//  Binds PUSH socket to tcp://localhost:5557
//  Sends batch of tasks to workers via that socket
//
//  Olivier Chamoux 
//
#include 
#include 
#include 
#include 
#include 

#define within(num) (int) ((float) num * random () / (RAND_MAX + 1.0))

int main (int argc, char *argv[])
{
    zmq::context_t context (1);

    //  Socket to send messages on
    zmq::socket_t  sender(context, ZMQ_PUSH);
    sender.bind("tcp://*:5557");

    std::cout << "Press Enter when the workers are ready: " << std::endl;
    getchar ();
    std::cout << "Sending tasks to workers...\n" << std::endl;

    //  Initialize random number generator
    srandom ((unsigned) time (NULL));

    //  Send 100 tasks
    int task_nbr;
    int total_msec = 0;     //  Total expected cost in msecs
    while (true) {
        int workload;
        //  Random workload from 1 to 100msecs
        workload = within (100) + 1;
        total_msec += workload;

        message.rebuild(10);
        memset(message.data(), '\0', 10);
        sprintf ((char *) message.data(), "%d", workload);
        sender.send(message);
        sleep (1);              //  Give 0MQ time to deliver
    }
    std::cout << "Total expected cost: " << total_msec << " msec" << std::endl;
    
    return 0;
}

python 接受任务,工作进程代码

import sys
import time
import zmq


context = zmq.Context()

# Socket to receive messages on
receiver = context.socket(zmq.PULL)
receiver.connect("tcp://localhost:5557")

# Process tasks forever
while True:
    b = receiver.recv()

    # Simple progress indicator for the viewer
    sys.stdout.write(str(b, encoding = "utf-8"))
    sys.stdout.flush()

python 发布任务进程

import sys
import time
import zmq


context = zmq.Context()

# Socket to receive messages on
receiver = context.socket(zmq.PULL)
receiver.connect("tcp://localhost:5557")

# Process tasks forever
while True:
    b = receiver.recv()

    # Simple progress indicator for the viewer
    sys.stdout.write(str(b, encoding = "utf-8"))
    sys.stdout.flush()

其它说明

  • 详细见:https://github.com/booksbyus/zguide

  • 一个任务下发进程,多个任务处理进程

  • linux机器可使用ipc://xx

  • 另外,可参考github上比较完整的例子: https://github.com/lyyiangang/zeromq_demo
    https://github.com/lyyiangang/zeromq_demo/tree/master/cvmat-cpp-py
    这个例子是将一个OpenCV的cv::Mat数据结构通过protobuf序列化,发送给一个python的subscriber.

你可能感兴趣的:(c++,python,zmq,多进程发布任务,分布式)