带有任务队列的多线程python(mp.Pool)服务器

带有任务队列的多线程python(mp.Pool)服务器,python,multithreading,server,queue,pool,Python,Multithreading,Server,Queue,Pool,因此,我正在为Autodesk Maya编写一个免费的python任务服务器,其中包含x个“工作者”的队列。在任何时候,服务器都可以接受一个“任务”,并将该任务扔到工作人员翻腾的队列中 从队列中,每个工作人员都会获得一个“taskDict”,这是一个发送到服务器的字典,其中说明了Maya文件的位置,以及打开无头Maya应用程序(mayapy.exe/standalone)时要运行的代码 我已经重写了很多次,首先使用我自己的队列系统,但后来我决定使用python的。接下来使用一个池,使用Queue

因此,我正在为Autodesk Maya编写一个免费的python任务服务器,其中包含x个“工作者”的队列。在任何时候,服务器都可以接受一个“任务”,并将该任务扔到工作人员翻腾的队列中

从队列中,每个工作人员都会获得一个“taskDict”,这是一个发送到服务器的字典,其中说明了Maya文件的位置,以及打开无头Maya应用程序(mayapy.exe/standalone)时要运行的代码

我已经重写了很多次,首先使用我自己的队列系统,但后来我决定使用python的。接下来使用一个池,使用Queue.Queue,使用mp.Manager.Queue和pool等。我很难找到任何简单的多线程服务器示例,这些服务器接收信息并启动线程,但在收到太多请求时使用队列

我根本不知道如何将信息放入队列,让mp.pool搅动队列,启动使用该数据的应用异步进程,并在队列完成时通知队列

以下是代码的当前状态:

import tempfile
import os
import subprocess
import threading
import multiprocessing as mp
import socket
import sys

from PySide import QtGui, QtCore

import serverUtils

selfDirectory = os.path.dirname(__file__)
uiFile = selfDirectory + '/server.ui'
if os.path.isfile(uiFile):
    form_class, base_class = serverUtils.loadUiType(uiFile)
else:
    print('Cannot find UI file: ' + uiFile)


def show():
    global mayaTaskServerWindow
    try:
        mayaTaskServerWindow.close()
    except:
        pass

        mayaTaskServerWindow = mayaTaskServer()
        mayaTaskServerWindow.show()
    return mayaTaskServerWindow

class MayaTaskServer(base_class, form_class):
    refreshSignal = QtCore.Signal()

    def __init__(self):
        super(MayaTaskServer, self).__init__()

        self.setupUi(self)

        self.mainJobServer = None
        self.mpPool = None
        self.manager = None
        self.q = None

        self.workerDict = {}

        self.refreshSignal.connect(self.refreshTree)
        self.startLocalCoresBTN.clicked.connect(self.startLocalCoresFn)
        self.killLocalCoresBTN.clicked.connect(self.killLocalCoresFn)
        self.jobTree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.jobTree.customContextMenuRequested.connect(self.openMenu)

        self.startJobServer(6006)
        self.startQueue()

        # set the default temp folder
        filepath = os.path.realpath(__file__)
        self.localTempFolderEDT.setText(filepath.replace(filepath.split('\\')[-1], ''))

    ## JOB SYSTEM
    ####################################################################

    class MayaWorker(object):
        def __init__(self, host, port, cpuID):
            self.host = host
            self.port = port
            self.location = None
            self.cpuID = cpuID

            self.location = self.host

            self.busy = False
            self.task = None
            self.taskHistory = {}

        def runTask(self, task):
            print 'starting task - ', self.task['description']
            self.busy = True
            serverUtils.spawnMaya(task)
            win.refreshSignal.emit()

        def taskComplete(self, arg):
            self.busy = False
            self.task = None
            self.mayaFile = None
            win.refreshSignal.emit()

    def bootUpLocalWorkers(self, numProcs):
        self.mpPool = mp.Pool(processes=numProcs)
        for i in range(0, numProcs):
            mw = self.MayaWorker('localhost', 6006, i)
            win.mpPool.apply_async(mw, args=(win.q))
            win.workerDict['CPU_' + str(i)] = mw

    ## USER INTERFACE
    ####################################################################

    #UI code here you don't care about

    ## JOB LISTENER / SERVER / QUEUE
    ####################################################################
    class JobServer(threading.Thread):
        def __init__(self, port):
            threading.Thread.__init__(self)
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.bind(('localhost', port))
            self.server_socket.listen(5)

            self.port = port
            self.running = True

            self.mpPool = None

        def addToQueue(self, task):
            #add to queue
            win.q.put(task, timeout=1000)

            #update UI
            wid1 = QtGui.QTreeWidgetItem()
            wid1.setText(0, str(task))
            win.queTree.addTopLevelItem(wid1)

        def run(self, debug=1):
            print 'Starting Task Server @' + socket.gethostbyname(socket.gethostname()) + ':' + str(self.port)
            while self.running:
                client_socket, address = self.server_socket.accept()
                ip = str(address[0])
                data = client_socket.recv(512)
                if 'runTask' in data:
                    taskDict = eval(data.split(' >> ')[-1])
                    print 'SERVER>> Received task:', str(taskDict)
                    self.addToQueue(taskDict)

    class TaskQueueServer(threading.Thread):
        def __init__(self):
            q = self.q_in
            while True:
                if self.q_in:
                    worker = win.findLocalWorker()
                    if worker:
                        taskDict = self.q_in[0]
                        worker.task = taskDict
                        worker.startTask()
                        self.q_in.pop[0]


    def startJobServer(self, port):
        self.mainJobServer = self.JobServer(port)
        self.mainJobServer.start()

    def startQueue(self):
        self.manager = mp.Manager()
        self.q = self.manager.Queue()


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    win = MayaTaskServer()
    win.show()
    sys.exit(app.exec_())

我是这样做的。一个非常简单、实用的解决方案

我有一个名为'finaLocalWorker'的方法,您可以看到worker类可以被标记为'busy'。如果工作进程不忙,将向其发送传入任务

如果所有工作人员都很忙,那么传入的任务将添加到一个名为“self.q”的简单列表中

当辅助进程完成任务时,mpPool.apply\u async有一个回调,该回调将触发taskComplete方法。此方法显示“如果self.q,则获取列表中的[0]项并弹出(删除)它。否则就把自己标记为“不忙”

这允许溢出传入请求,例如在任务列表中排队的一批500个动画,但服务器仍然能够在一段时间内不接收任何任务,并立即处理传入的任何任务

我将把最后的代码放到github上