Сервер сокетов Python 3 concurrent.futures работает с ThreadPoolExecutor, но не с ProcessPoolExecutor

Я пытаюсь создать простой сервер сокетов, используя новые классы concurrent.futures. Я могу заставить его нормально работать с ThreadPoolExecutor, но он просто зависает, когда я использую ProcessPoolExecutor, и я не могу понять, почему. Учитывая обстоятельства, я подумал, что это может иметь какое-то отношение к попытке передать дочернему процессу что-то, что не может быть рассмотрено, но я не делаю этого. Ниже приведена упрощенная версия моего кода. Буду признателен за любой совет.

import concurrent.futures
import socket, os

HOST = ''
PORT = 9001

def request_handler(conn, addr):
    pid = os.getpid()
    print('PID', pid, 'handling connection from', addr)
    while True:
        data = conn.recv(1024)
        if not data:
            print('PID', pid, 'end connection')
            break
        print('PID', pid, 'received:', bytes.decode(data))
        conn.send(data)
    conn.close()

def main():
    with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            sock.bind((HOST, PORT))
            sock.listen(10)
            print("Server listening on port", PORT)
            while True:
                conn, addr = sock.accept()
                executor.submit(request_handler, conn, addr)
                conn.close()
            print("Server shutting down")


if __name__ == '__main__':
    main()

person ThatAintWorking    schedule 25.09.2011    source источник
comment
Если это помогает, то в Python 3.2 ProcessPoolExecutor, как известно, блокируется, если рабочий умирает плохо (например, без значения выхода 0).   -  person donkopotamus    schedule 26.09.2011
comment
Хороший звонок @Donkopotamus, вы должны были опубликовать это как ответ, а не комментарий.   -  person ThatAintWorking    schedule 26.09.2011


Ответы (2)


Хороший звонок Донкопотамусу, ты должен был опубликовать это как ответ.

Я заключил обработчик в блок попытки, и когда он пытается вызвать conn.recv (), я получил исключение: [Errno 10038] Была предпринята попытка выполнения операции с чем-то, что не является сокетом. Поскольку рабочий процесс сильно умирал, он зашел в тупик. Установив блок try, улавливающий ошибку, я могу продолжать подключаться столько, сколько захочу, без каких-либо взаимоблокировок.

Я не получаю эту ошибку, если изменю код для использования ThreadPoolExecutor. Я пробовал несколько вариантов, и похоже, что нет способа правильно передать сокет рабочему процессу в ProcessPoolExecutor. Я нашел другие ссылки на это в Интернете, но они говорят, что это можно сделать на некоторых платформах, но не на других. Я пробовал его в Windows, Linux и MacOS X, и он не работает ни на одном из них. Это кажется существенным ограничением.

person ThatAintWorking    schedule 26.09.2011

вы уверены, что это не вызвано conn.close () после того, как вы запустили executeor.submit (...)? Я просто удаляю строку и пробую на mac10.12.6 и python 3.6.3 все работает хорошо.

person jon    schedule 16.12.2017