Ben*_*lls 2 python sockets multithreading
我对使用套接字和多线程编程的经验很少,所以为了了解更多,我决定看看我是否可以将一个小的python套接字服务器连接起来为聊天室供电.我最终让它工作得很好,但后来我注意到当我在后台运行时,我的服务器CPU使用率飙升超过100%.
这是我的完整代码:http://gist.github.com/332132
我知道这是一个非常开放的问题,所以除了帮助我的代码之外,还有什么好的文章我可以阅读,可以帮助我了解更多这方面的内容吗?
我的完整代码:
import select
import socket
import sys
import threading
from daemon import Daemon
class Server:
def __init__(self):
self.host = ''
self.port = 9998
self.backlog = 5
self.size = 1024
self.server = None
self.threads = []
self.send_count = 0
def open_socket(self):
try:
self.server = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server.bind((self.host,self.port))
self.server.listen(5)
print "Server Started..."
except socket.error, (value,message):
if self.server:
self.server.close()
print "Could not open socket: " + message
sys.exit(1)
def remove_thread(self, t):
t.join()
def send_to_children(self, msg):
self.send_count = 0
for t in self.threads:
t.send_msg(msg)
print 'Sent to '+str(self.send_count)+" of "+str(len(self.threads))
def run(self):
self.open_socket()
input = [self.server,sys.stdin]
running = 1
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for s in inputready:
if s == self.server:
# handle the server socket
c = Client(self.server.accept(), self)
c.start()
self.threads.append(c)
print "Num of clients: "+str(len(self.threads))
self.server.close()
for c in self.threads:
c.join()
class Client(threading.Thread):
def __init__(self,(client,address), server):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
self.server = server
self.running = True
def send_msg(self, msg):
if self.running:
self.client.send(msg)
self.server.send_count += 1
def run(self):
while self.running:
data = self.client.recv(self.size)
if data:
print data
self.server.send_to_children(data)
else:
self.running = False
self.server.threads.remove(self)
self.client.close()
"""
Run Server
"""
class DaemonServer(Daemon):
def run(self):
s = Server()
s.run()
if __name__ == "__main__":
d = DaemonServer('/var/servers/fserver.pid')
if len(sys.argv) == 2:
if 'start' == sys.argv[1]:
d.start()
elif 'stop' == sys.argv[1]:
d.stop()
elif 'restart' == sys.argv[1]:
d.restart()
else:
print "Unknown command"
sys.exit(2)
sys.exit(0)
else:
print "usage: %s start|stop|restart" % sys.argv[0]
sys.exit(2)
Run Code Online (Sandbox Code Playgroud)
您的代码中有几种可能的竞争条件,但它们会威胁正确性而不是性能:修复它们,例如通过锁定肯定不会提高性能.
相反,我会专注于你认为那些线程正在做的好事 - 因为你的代码的核心是一个select.select调用,为什么不专注于那个......以及一个完全异步,因此更有效...服务器而不是将一些任务反弹到基本上只是开销的线程.在某些输入准备就绪时读取(正如您所做的那样),在某个套接字准备好输出时写入,&c - 它比当前的线程和异步混合更简单,更快.
直接在异步服务器上编程select.select是一种相当低级的方法,虽然它具有指导性,但它并不适合生产.考虑使用asyncore和asynchatPython标准库模块的适度更高的抽象水平,或twisted第三方包一个更高的提升(包括更有效的手段,而不是老来实现底层的"反应堆"设计模式的能力select-有poll,kqueues等,取决于你所使用的操作系统,Twisted可以让你根据你的平台选择实现,同时保持相同的Reactor接口).
我想,我盖住这些各种可能性体面,如果简明,在"服务器端套接字"果壳中的第二版的Python章 - 你可以通过获取试用订阅O'Reilly的"野生动物园在线"获得免费在线现场,或(通过查找和使用许多盗版网站主办的书籍(假设当然盗版复制你不想用得到它"一切合法和适当" ;-)花钱为它的一个非法;-).我想你无论如何都可以免费下载带有O'Reilly网站所有示例代码的zip文件.
| 归档时间: |
|
| 查看次数: |
2708 次 |
| 最近记录: |