具有异步功能的Python多处理

时间:2019-03-10 13:37:31

标签: python-3.x websocket async-await python-multiprocessing python-asyncio

我构建了一个websocket服务器,其简化版本如下所示:

import websockets, subprocess, asyncio, json, re, os, sys
from multiprocessing import Process

def docker_command(command_words):
    return subprocess.Popen(
        ["docker"] + command_words,
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)

async def check_submission(websocket:object, submission:dict):
    exercise=submission["exercise"]
    with docker_command(["exec", "-w", "badkan", "grade_exercise", exercise]) as proc:
        for line in proc.stdout:
            print("> " + line)
            await websocket.send(line)

async def run(websocket, path):
    submission_json = await websocket.recv()   # returns a string
    submission = json.loads(submission_json)   # converts the string to a python dict

    ####
    await check_submission(websocket, submission)


websocketserver = websockets.server.serve(run, '0.0.0.0', 8888, origins=None)
asyncio.get_event_loop().run_until_complete(websocketserver)
asyncio.get_event_loop().run_forever()

当一次只有一个用户时,它可以正常工作。但是,当几个用户尝试使用服务器时,服务器会顺序处理它们,因此以后的用户必须等待很长时间。

我试图通过将标有“ ####”(“ await check_submission ...”)的行替换为:来将其转换为多处理服务器,

p = Process(target=check_submission, args=(websocket, submission,))
p.start()

但是,它不起作用-我收到了运行时警告:“协程:从未等待'check_submission'”,并且我没有看到通过websocket发出的任何输出。

我还尝试将这些行替换为:

loop = asyncio.get_event_loop()
loop.set_default_executor(ProcessPoolExecutor())
await loop.run_in_executor(None, check_submission, websocket, submission)

但是出现了另一个错误:“无法腌制asyncio.Future对象”。

如何构建此多处理websocket服务器?

2 个答案:

答案 0 :(得分:1)

问题是import pygame from tkinter import * from tkinter import filedialog pygame.mixer.init(frequency=44100, size=-16, channels=2, buffer=512) pygame.init() root = Tk() audio_file_name1 = '' def open_masker1(): global audio_file_name1 audio_file_name1 = filedialog.askopenfilename(filetypes=(("Audio Files", ".wav .ogg"), ("All Files", "*.*"))) def playsound1(): # we will also use the audio_file_name global variable global audio_file_name1 if audio_file_name1: # play sound if just not an empty string noise = pygame.mixer.Sound(audio_file_name1) noise.play() b1 = Button(root, text = 'open file',command = open_masker1) # browser button 1 b1.pack(anchor=CENTER) p1 = Button(root, text = 'Som1', command = playsound1) # playsound1 p1.pack(anchor=W) root.mainloop() 不是异步的,所以subprocess.Popen在等待下一行docker输出时会阻塞事件循环。

您根本不需要使用多处理;由于您在等待子流程时正在阻塞,因此只需要从check_submission切换到subprocess

asyncio.subprocess

答案 1 :(得分:0)

这是我的示例,asyncio.run()为我工作,使用多进程启动异步功能

class FlowConsumer(Base):
    def __init__(self):
        pass

    async def run(self):
        self.logger("start consumer process")
        while True:
            # get flow from queue
            flow = {}
            # call flow executor get result
            executor = FlowExecutor(flow)
            rtn = FlowResult()
            try:
                rtn = await executor.run()
            except Exception as e:
                self.logger("flow run except:{}".format(traceback.format_exc()))
                rtn.status = FLOW_EXCEPT
                rtn.msg = str(e)
            self.logger("consumer flow finish,result:{}".format(rtn.dict()))
            time.sleep(1)

    def process(self):
        asyncio.run(self.run())


processes = []
consumer_proc_count = 3

# start multi consumer processes 
for _ in range(consumer_proc_count):
    # old version
    # p = Process(target=FlowConsumer().run)
    p = Process(target=FlowConsumer().process)
    p.start()
    processes.append(p)

for p in processes:
    p.join()