zeromq push-pull 模式

举一个例子,在并行处理中的一个经典情形。一个任务分发者拆解任务并进行分配,很多执行者领取任务然后执行,最后执行者将结果发送给一个收集者。见下图:
zeromq push-pull 模式_第1张图片
- 最上面是产生任务的 分发者 ventilator
- 中间是执行者 worker
- 下面是收集结果的接收者 sink

任务分发者首先给接受者sink发送“0”表示开始处理,然后给执行者发送一个休眠时间代表它的工作负载。

//  Task ventilator
//  Binds PUSH socket to tcp://localhost:5557
//  Sends batch of tasks to workers via that socket

#include "zhelpers.h"

int main (void)
{
    void *context = zmq_ctx_new ();

    //  Socket to send messages on
    void *sender = zmq_socket (context, ZMQ_PUSH);
    zmq_bind (sender, "tcp://*:5557");

    //  Socket to send start of batch message on
    void *sink = zmq_socket (context, ZMQ_PUSH);
    zmq_connect (sink, "tcp://localhost:5558");

    printf ("Press Enter when the workers are ready: ");
    getchar ();
    printf ("Sending tasks to workers…\n");

    //  The first message is "0" and signals start of batch
    s_send (sink, "0");

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

    //  Send 100 tasks
    int task_nbr;
    int total_msec = 0;     //  Total expected cost in msecs
    for (task_nbr = 0; task_nbr < 100; task_nbr++) {
        int workload;
        //  Random workload from 1 to 100msecs
        workload = randof (100) + 1;
        total_msec += workload;
        char string [10];
        sprintf (string, "%d", workload);
        s_send (sender, string);
    }
    printf ("Total expected cost: %d msec\n", total_msec);

    zmq_close (sink);
    zmq_close (sender);
    zmq_ctx_destroy (context);
    return 0;
}

执行者简单的从分配者哪里拉取任务,根据任务休眠时间休眠。然后它简单的向收集信息的sink发送结果,周而复始。

//  Task worker
//  Connects PULL socket to tcp://localhost:5557
//  Collects workloads from ventilator via that socket
//  Connects PUSH socket to tcp://localhost:5558
//  Sends results to sink via that socket

#include "zhelpers.h"

int main (void)
{
    //  Socket to receive messages on
    void *context = zmq_ctx_new ();
    void *receiver = zmq_socket (context, ZMQ_PULL);
    zmq_connect (receiver, "tcp://localhost:5557");

    //  Socket to send messages to
    void *sender = zmq_socket (context, ZMQ_PUSH);
    zmq_connect (sender, "tcp://localhost:5558");

    //  Process tasks forever
    while (1) {
        char *string = s_recv (receiver);
        printf ("%s.", string);     //  Show progress
        fflush (stdout);
        s_sleep (atoi (string));    //  Do the work
        free (string);
        s_send (sender, "");        //  Send results to sink
    }
    zmq_close (receiver);
    zmq_close (sender);
    zmq_ctx_destroy (context);
    return 0;
}

收集者sink接收到开始信号开始计时,在接收到100个任务结果后结束,并打印用时。

//  Task sink
//  Binds PULL socket to tcp://localhost:5558
//  Collects results from workers via that socket

#include "zhelpers.h"

int main (void)
{
    //  Prepare our context and socket
    void *context = zmq_ctx_new ();
    void *receiver = zmq_socket (context, ZMQ_PULL);
    zmq_bind (receiver, "tcp://*:5558");

    //  Wait for start of batch
    char *string = s_recv (receiver);
    free (string);

    //  Start our clock now
    int64_t start_time = s_clock ();

    //  Process 100 confirmations
    int task_nbr;
    for (task_nbr = 0; task_nbr < 100; task_nbr++) {
        char *string = s_recv (receiver);
        free (string);
        if ((task_nbr / 10) * 10 == task_nbr)
            printf (":");
        else
            printf (".");
        fflush (stdout);
    }
    //  Calculate and report duration of batch
    printf ("Total elapsed time: %d msec\n",
        (int) (s_clock () - start_time));

    zmq_close (receiver);
    zmq_ctx_destroy (context);
    return 0;
}

当我们开始1,2,或者4个执行者是,我们的到的结果是这样的。
1个执行者:total elapsed time :5034ms
2个执行者:total elapsed time :2421ms
4个执行者:total elapsed time :1018ms
然我们跟深入的谈下这些代码的细节:
- 该模型中执行者worker可以自由的进行扩容,分发者和收集者是一个固定的结果,而worker可以自由的调整。
- 我们必须同步执行者的批次起点。这在zeromq中是一个相当普遍的难题,没有简单的解决方案。zmq_connect方法执行需要时间,因此当一批执行者链接到分发者,第一个成功进行链接并且成功取得负载消息,在此期间其他的执行者也在链接。如果我们不同步批次同步会如何,这个系统将不能并行。试试去掉延时看看会发生什么。
- 假设分发者的PUSH socket分发任务给执行者均匀的(假设它们全部在开始前链接好)。这就是”load balancing”(负载均衡)。
- 收集者的PULL socket收集结果均匀,这就叫做”fair-queuing”(公平排队)
zeromq push-pull 模式_第2张图片
pipeline模式也展现出”slow joiner”特征,导致指责PUSH socket不具有负载均衡特性。如果你使用push pull模式,你的其中一个执行者比其他得到跟多的消息,那是因为该执行者的push socket有更快的接速度比其他的,如果你想适当的负载均匀,你可能要使用request-reply模式。

原文
这里写链接内容

你可能感兴趣的:(zeromq,lua,c++,ios)