Выбрать главу

redis_choc_supply.py передает бесконечное количество конфет:

import redis

import random

from time import sleep

conn = redis.Redis()

varieties = ['truffle', 'cherry', 'caramel', 'nougat']

conveyor = 'chocolates'

while True:

····seconds = random.random()

····sleep(seconds)

····piece = random.choice(varieties)

····conn.rpush(conveyor, piece)

redis_lucy.py может выглядеть так:

import redis

from datetime import datetime

from time import sleep

conn = redis.Redis()

timeout = 10

conveyor = 'chocolates'

while True:

····sleep(0.5)

····msg = conn.blpop(conveyor, timeout)

····remaining = conn.llen(conveyor)

····if msg:

········piece = msg[1]

········print('Lucy got a', piece, 'at', datetime.utcnow(),

········', only', remaining, 'left')

Запустите их в любом порядке. Поскольку Люси требуется полсекунды для обработки каждой конфеты и они появляются в среднем каждые полсекунды, это становится похоже на гонку. Чем раньше вы запустите конвейер, тем более сложной сделаете жизнь Люси:

$ python redis_choc_supply.py&

$ python redis_lucy.py

Lucy got a b'nougat' at 2014-06-03 03:15:08.721169, only 4 left

Lucy got a b'cherry' at 2014-06-03 03:15:09.222816, only 3 left

Lucy got a b'truffle' at 2014-06-03 03:15:09.723691, only 5 left

Lucy got a b'truffle' at 2014-06-03 03:15:10.225008, only 4 left

Lucy got a b'cherry' at 2014-06-03 03:15:10.727107, only 4 left

Lucy got a b'cherry' at 2014-06-03 03:15:11.228226, only 5 left

Lucy got a b'cherry' at 2014-06-03 03:15:11.729735, only 4 left

Lucy got a b'truffle' at 2014-06-03 03:15:12.230894, only 6 left

Lucy got a b'caramel' at 2014-06-03 03:15:12.732777, only 7 left

Lucy got a b'cherry' at 2014-06-03 03:15:13.234785, only 6 left

Lucy got a b'cherry' at 2014-06-03 03:15:13.736103, only 7 left

Lucy got a b'caramel' at 2014-06-03 03:15:14.238152, only 9 left

Lucy got a b'cherry' at 2014-06-03 03:15:14.739561, only 8 left

Бедная Люси.

5. Используйте ZeroMQ, чтобы публиковать стихотворение из упражнения 7 главы 7 по одному слову за раз. Напишите потребителя ZeroMQ, который будет выводить на экран каждое слово, начинающееся с гласной. Напишите другого потребителя, который будет выводить все слова, состоящие из пяти букв. Знаки препинания игнорируйте.

Так выглядит сервер, poem_pub.py, который отщипывает по одному слову стихотворения и публикует его в тему vowels, если оно начинается с гласной, и в тему five, если состоит из пяти букв. Некоторые слова могут оказаться в обеих темах, некоторые — ни в одной:

import string

import zmq

host = '127.0.0.1'

port = 6789

ctx = zmq.Context()

pub = ctx.socket(zmq.PUB)

pub.bind('tcp://%s:%s' % (host, port))

with open('mammoth.txt', 'rt') as poem:

····words = poem.read()

for word in words.split():

····word = word.strip(string.punctuation)

····data = word.encode('utf-8')

····if word.startswith(('a','e','i','o','u','A','e','i','o','u')):

········pub.send_multipart([b'vowels', data])

····if len(word) == 5:

········pub.send_multipart([b'five', data])

Клиент poem_sub.py подписывается на темы vowels и five и выводит на экран тему и слово:

import string

import zmq

host = '127.0.0.1'

port = 6789

ctx = zmq.Context()

sub = ctx.socket(zmq.SUB)

sub.connect('tcp://%s:%s' % (host, port))

sub.setsockopt(zmq.SUBSCRIBE, b'vowels')

sub.setsockopt(zmq.SUBSCRIBE, b'five')

while True:

····topic, word = sub.recv_multipart()

····print(topic, word)

Если вы запустите эти программы, они не будут работать, хотя код выглядит хорошо. Вам нужно прочитать руководство ZeroMQ, чтобы узнать о проблеме медленного присоединившегося: даже если вы запустите клиент раньше сервера, сервер начнет отправлять данные сразу после запуска, а клиенту потребуется некоторое время, чтобы подключиться к серверу. Если вы публикуете сообщения постоянным потоком и не задумываетесь о том, когда к вам подключаются подписчики, это не проблема. Но в этом случае поток данных настолько короткий, что он заканчивается еще до того, как подписчик успеет моргнуть.

Простейший способ исправить это — заставить публикатора пропустить секунду после вызова метода bind() и до того, как он начнет отправлять сообщения. Назовем эту версию poem_pub_sleep.py:

import string

import zmq

from time import sleep

host = '127.0.0.1'

port = 6789

ctx = zmq.Context()

pub = ctx.socket(zmq.PUB)

pub.bind('tcp://%s:%s' % (host, port))

sleep(1)

with open('mammoth.txt', 'rt') as poem: