我正在尝试在python中创建一个多进程,多线程程序。到目前为止,我已经取得了成功,但我遇到了一个困扰我的问题。
我有3节课。主类是Manager,它创建一个或多个子流程(Subprocess类),并使用专用的multiprocessing.Queue连接到每个子流程。然后,它通过队列发送这些子进程命令以创建套接字管理线程(Server_Thread类)。 Server_Thread的配置选项在Manager类中创建,并以字典的形式通过队列传递给子进程。
代码如下
import threading
import multiprocessing
import socket
import time
class Server_Thread(threading.Thread):
def __init__(self, client_config):
threading.Thread.__init__(self)
self.address = client_config['address']
self.port = client_config['port']
def run(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "Binding to: local host, port = ", self.port
self.socket.bind((socket.gethostname(), self.port))
self.socket.listen(1)
self.running = True
while self.running:
client_socket, client_address = self.socket.accept()
# do stuff
def stop(self):
self.running = False
class Subprocess(multiprocessing.Process):
def __init__(self, queue):
multiprocessing.Process.__init__(self)
self.queue = queue
self.server_thread_list = []
def run(self):
self.running = True
while self.running:
command = self.queue.get()
if command[0] == "create_client":
server_thread = Server_Thread(command[1])
server_thread.start()
self.server_thread_list.append(server_thread)
elif command[0] == "terminate":
self.running = False
for server_thread in self.server_thread_list:
server_thread.stop()
server_thread.join()
class Manager:
def __init__(self):
self.client_config = {}
self.client_config['junk'] = range(10000) # actually contains lots of stuff
self.client_config['address'] = 'localhost'
def run(self):
current_bind_port = 40001
self.queue = multiprocessing.Queue()
subprocess = Subprocess(self.queue)
subprocess.start()
for i in range(20):
print "creating socket thread at port =", current_bind_port
self.client_config['port'] = current_bind_port
self.queue.put(("create_client", self.client_config.copy())) # pass a dictionary copy
current_bind_port += 1
time.sleep(10)
self.queue.put(("terminate", None))
subprocess.join()
if __name__ == "__main__":
manager = Manager()
manager.run()
问题在于,当我运行它时,有时它运行正常,但有时,配置字典在队列中搞砸了。我认为这与填充队列的速度和清空的速度有关,我认为它会在没有警告的情况下溢出。
带有一些重组的输出(多个进程混合了打印)
>Python temp.py
creating socket thread at port = 40001
creating socket thread at port = 40002
creating socket thread at port = 40003
creating socket thread at port = 40004
creating socket thread at port = 40005
creating socket thread at port = 40006
creating socket thread at port = 40007
creating socket thread at port = 40008
creating socket thread at port = 40009
creating socket thread at port = 40010
creating socket thread at port = 40011
creating socket thread at port = 40012
creating socket thread at port = 40013
creating socket thread at port = 40014
creating socket thread at port = 40015
creating socket thread at port = 40016
creating socket thread at port = 40017
creating socket thread at port = 40018
creating socket thread at port = 40019
creating socket thread at port = 40020 << OK
Binding to: local host, port = 40001
Binding to: local host, port = 40020 << NOT OK from here
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Binding to: local host, port = 40020
Exception in thread Thread-4:
Traceback (most recent call last):
File "C:\Python27\lib\threading.py", line 810, in __bootstrap_inner
self.run()
File "Y:\cStation\Python\iReact connection PoC\temp.py", line 18, in run
self.socket.bind((socket.gethostname(), self.port))
File "C:\Python27\lib\socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
error: [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
.... Get this message several more times ....
如果在将每个create_thread命令放入队列后插入'time.sleep(0.1)'命令,问题似乎变得不那么频繁(但不会完全消失)。
有趣的是,带有"create_thread"
命令的元组在没有问题的情况下被转移,问题似乎是值的字典。在没有time.wait()
的情况下将值放入其中之前,有没有办法确保队列可以写入?我试过放一个while not self.queue.empty(): pass
,但在几个命令之后似乎永远陷入困境......