这个问题与我在这里提出的其他问题有关,主要是关于在内存中分类大量数据。
基本上这就是我想要的东西:
Twisted XMLRPC服务器正在运行。该服务器在内存中保留了几(10)个Foo类实例。每个Foo类都包含一个列表栏(包含数百万条记录)。有一项服务从数据库中检索数据,并将其传递给XMLRPC服务器。数据基本上是一个字典,其中的键对应于每个Foo实例,值是一个字典列表,如下所示:
data = {'foo1':[{'k1':'v1', 'k2':'v2'}, {'k1':'v1', 'k2':'v2'}], 'foo2':...}
然后传递每个Foo实例与其键对应的值,并更新和排序Foo.bar词典。
class XMLRPCController(xmlrpc.XMLRPC):
def __init__(self):
...
self.foos = {'foo1':Foo(), 'foo2':Foo(), 'foo3':Foo()}
...
def update(self, data):
for k, v in data:
threads.deferToThread(self.foos[k].processData, v)
def getData(self, fookey):
# return first 10 records of specified Foo.bar
return self.foos[fookey].bar[0:10]
class Foo():
def __init__(self):
bar = []
def processData(self, new_bar_data):
for record in new_bar_data:
# do processing, and add record, then sort
# BUNCH OF PROCESSING CODE
self.bar.sort(reverse=True)
问题是当在具有大量记录(比如100K +)的XMLRPCController中调用更新函数时,它会停止响应我的getData调用,直到所有32个Foo实例都完成了process_data方法。我认为deferToThread可行,但我认为我误解了问题所在。
任何建议......我愿意使用其他东西,比如Cherrypy,如果它支持这种必要的行为。
修改
@Troy:这就是反应堆的设置方式
reactor.listenTCP(port_no, server.Site(XMLRPCController)
reactor.run()
就GIL而言,改变是否可行 sys.setcheckinterval() 值为较小的值,因此对数据的锁定被释放以便可以读取?
答案 0 :(得分:1)
让应用程序响应的最简单方法是在较小的块中分解CPU密集型处理,同时让扭曲的反应器在两者之间运行。例如,通过调用reactor.callLater(0,process_next_chunk)来前进到下一个块。有效地实施合作多任务处理。
另一种方法是使用单独的流程来完成工作,然后您将受益于多个核心。看看Ampoule:https://launchpad.net/ampoule它提供了类似于deferToThread的API。
答案 1 :(得分:0)
我不知道您的processData方法运行了多长时间,也不知道您是如何设置扭曲反应堆的。 By default,扭曲的反应器有一个0到10个线程的线程池。您可能正在尝试将多达32个长时间运行的计算推迟到多达10个线程。这是次优的。
您还需要询问GIL在更新所有这些集合时扮演的角色。
编辑:
在对程序进行任何重大更改之前(如调用sys.setcheckinterval()
),您应该使用探查器或python跟踪模块来运行它。这些应该告诉你使用所有时间的方法。没有正确的信息,您无法做出正确的更改。