function main() { for ($client_nbr = 0; $client_nbr < NBR_CLIENTS; $client_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { client_thread(); return; } } for ($worker_nbr = 0; $worker_nbr < NBR_WORKERS; $worker_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { worker_thread(); return; } } $context = new ZMQContext(); $frontend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $backend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $frontend->bind("ipc://frontend.ipc"); $backend->bind("ipc://backend.ipc"); // Logic of LRU loop // - Poll backend always, frontend only if 1+ worker ready // - If worker replies, queue worker as ready and forward reply // to client if necessary // - If client requests, pop next worker and send request to it // Queue of available workers $available_workers = 0; $worker_queue = array(); $writeable = $readable = array(); while ($client_nbr > 0) { $poll = new ZMQPoll(); // Poll front-end only if we have available workers if ($available_workers > 0) { $poll->add($frontend, ZMQ::POLL_IN); } // Always poll for worker activity on backend $poll->add($backend, ZMQ::POLL_IN); $events = $poll->poll($readable, $writeable); if ($events > 0) { foreach ($readable as $socket) { // Handle worker activity on backend if ($socket === $backend) { // Queue worker address for LRU routing $worker_addr = $socket->recv(); assert($available_workers < NBR_WORKERS); $available_workers++; array_push($worker_queue, $worker_addr); // Second frame is empty $empty = $socket->recv(); assert(empty($empty)); // Third frame is READY or else a client reply address $client_addr = $socket->recv(); if ($client_addr != "READY") { $empty = $socket->recv(); assert(empty($empty)); $reply = $socket->recv(); $frontend->send($client_addr, ZMQ::MODE_SNDMORE); $frontend->send("", ZMQ::MODE_SNDMORE); $frontend->send($reply); // exit after all messages relayed $client_nbr--; } } elseif ($socket === $frontend) { // Now get next client request, route to LRU worker // Client request is [address][empty][request] $client_addr = $socket->recv(); $empty = $socket->recv(); assert(empty($empty)); $request = $socket->recv(); $backend->send(array_shift($worker_queue), ZMQ::MODE_SNDMORE); $backend->send("", ZMQ::MODE_SNDMORE); $backend->send($client_addr, ZMQ::MODE_SNDMORE); $backend->send("", ZMQ::MODE_SNDMORE); $backend->send($request); $available_workers--; } } } } // Clean up our worker processes foreach ($worker_queue as $worker) { $backend->send($worker, ZMQ::MODE_SNDMORE); $backend->send("", ZMQ::MODE_SNDMORE); $backend->send('END'); } sleep(1); }
function main() { for ($client_nbr = 0; $client_nbr < NBR_CLIENTS; $client_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { client_thread(); return; } } for ($worker_nbr = 0; $worker_nbr < NBR_WORKERS; $worker_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { worker_thread(); return; } } $context = new ZMQContext(); $frontend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $backend = new ZMQSocket($context, ZMQ::SOCKET_ROUTER); $frontend->bind("ipc://frontend.ipc"); $backend->bind("ipc://backend.ipc"); // Logic of LRU loop // - Poll backend always, frontend only if 1+ worker ready // - If worker replies, queue worker as ready and forward reply // to client if necessary // - If client requests, pop next worker and send request to it // Queue of available workers $available_workers = 0; $worker_queue = array(); $writeable = $readable = array(); while ($client_nbr > 0) { $poll = new ZMQPoll(); // Poll front-end only if we have available workers if ($available_workers > 0) { $poll->add($frontend, ZMQ::POLL_IN); } // Always poll for worker activity on backend $poll->add($backend, ZMQ::POLL_IN); $events = $poll->poll($readable, $writeable); if ($events > 0) { foreach ($readable as $socket) { // Handle worker activity on backend if ($socket === $backend) { // Queue worker address for LRU routing $zmsg = new Zmsg($socket); $zmsg->recv(); assert($available_workers < NBR_WORKERS); $available_workers++; array_push($worker_queue, $zmsg->unwrap()); if ($zmsg->body() != "READY") { $zmsg->set_socket($frontend)->send(); // exit after all messages relayed $client_nbr--; } } else { if ($socket === $frontend) { $zmsg = new Zmsg($socket); $zmsg->recv(); $zmsg->wrap(array_shift($worker_queue), ""); $zmsg->set_socket($backend)->send(); $available_workers--; } } } } } // Clean up our worker processes foreach ($worker_queue as $worker) { $zmsg = new Zmsg($backend); $zmsg->body_set('END')->wrap($worker, "")->send(); } sleep(1); }
if ($_SERVER['argc'] < 2) { echo "syntax: peering2 me {you}...", PHP_EOL; exit; } $self = $_SERVER['argv'][1]; for ($client_nbr = 0; $client_nbr < NBR_CLIENTS; $client_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { client_thread($self); return; } } for ($worker_nbr = 0; $worker_nbr < NBR_WORKERS; $worker_nbr++) { $pid = pcntl_fork(); if ($pid == 0) { worker_thread($self); return; } } printf("I: preparing broker at %s... %s", $self, PHP_EOL); // Prepare our context and sockets $context = new ZMQContext(); // Bind cloud frontend to endpoint $cloudfe = $context->getSocket(ZMQ::SOCKET_XREP); $endpoint = sprintf("ipc://%s-cloud.ipc", $self); $cloudfe->setSockOpt(ZMQ::SOCKOPT_IDENTITY, $self); $cloudfe->bind($endpoint); // Connect cloud backend to all peers $cloudbe = $context->getSocket(ZMQ::SOCKET_XREP); $cloudbe->setSockOpt(ZMQ::SOCKOPT_IDENTITY, $self); for ($argn = 2; $argn < $_SERVER['argc']; $argn++) {
// Tell the router we're ready for work $worker->send("ready"); // Get workload from router, until finished $workload = $worker->recv(); if ($workload == 'END') { printf("Processed: %d tasks%s", $total, PHP_EOL); break; } $total++; // Do some random work usleep(mt_rand(1, 1000000)); } } for ($worker_nbr = 0; $worker_nbr < NBR_WORKERS; $worker_nbr++) { if (pcntl_fork() == 0) { worker_thread(); exit; } } $context = new ZMQContext(); $client = $context->getSocket(ZMQ::SOCKET_ROUTER); $client->bind("ipc://routing.ipc"); for ($task_nbr = 0; $task_nbr < NBR_WORKERS * 10; $task_nbr++) { // LRU worker is next waiting in queue $address = $client->recv(); $empty = $client->recv(); $read = $client->recv(); $client->send($address, ZMQ::MODE_SNDMORE); $client->send("", ZMQ::MODE_SNDMORE); $client->send("This is the workload"); }