我的程序基本上必须从数据库中获取大约6000个项目,并为每个项目调用外部API。这几乎需要30分钟才能完成。我只是想在这里使用线程,我可以创建多线程并分割进程并减少时间。所以我提出了这样的事情。但我在这里有两个问题。如何存储函数处理的API的响应。
api = externalAPI()
for x in instruments:
response = api.getProcessedItems(x.symbol, days, return_perc);
if(response > float(return_perc)):
return_response.append([x.trading_symbol, x.name, response])
所以在上面的例子中,for循环运行了6000次(len(instruments) == 6000
)
现在让我把6000件物品分成2 * 3000件物品并做这样的事情
class externalApi:
def handleThread(self, symbol, days, perc):
//I call the external API and process the items
// how do i store the processed data
def getProcessedItems(self,symbol, days, perc):
_thread.start_new_thread(self.handleThread, (symbol, days, perc))
_thread.start_new_thread(self.handleThread, (symbol, days, perc))
return self.thread_response
我刚刚开始使用线程。如果我知道这是减少时间的正确方法,那将会很有帮助。
P.S:时间在这里很重要。我想从30分钟缩短到1分钟。答案 0 :(得分:0)
我建议使用worker-queue模式,如此......
你将拥有一个工作队列,每个工作人员将接受一份工作并对其进行处理,结果将放在另一个队列中,当所有工人完成时,将读取结果队列并处理结果
def worker(pool, result_q):
while True:
job = pool.get()
result = handle(job) #handle job
result_q.put(result)
pool.task_done()
q = Queue.Queue()
res_q = Queue.Queue()
for i in range(num_worker_threads):
t = threading.Thread(target=worker, args=(q, res_q))
t.setDaemon(True)
t.start()
for job in jobs:
q.put(job)
q.join()
while not res_q.empty():
result = res_q.get()
# do smth with result
答案 1 :(得分:0)
shahaf's answer中建议的工作队列模式工作正常,但Python在concurret.futures
中提供更高级别的抽象。即ThreadPoolExecutor
,它将负责为您排队和启动线程:
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=30)
responses = executor.map(process_item, (x.symbol for x in instruments))
使用excutor.map()
的主要复杂因素是它只能映射一个参数,这意味着proces_item
只能有一个输入,即symbol
)。
但是,如果需要更多参数,则可以定义一个新函数,该函数将固定除一个参数之外的所有参数。这可以手动完成,也可以使用partial
中的特殊Python functools
调用完成:
from functools import partial
process_item = partial(api.handleThread, days=days, perc=return_perc)
将ThreadPoolExecutor
策略应用于您当前的问题,将有一个类似于以下的解决方案:
from concurrent.futures import ThreadPoolExecutor
from functools import partial
class Instrument:
def __init__(self, symbol, name):
self.symbol = symbol
self.name = name
instruments = [Instrument('SMB', 'Name'), Instrument('FNK', 'Funky')]
class externalApi:
def handleThread(self, symbol, days, perc):
# Call the external API and process the items
# Example, to give something back:
if symbol == 'FNK':
return days*3
else:
return days
def process_item_generator(api, days, perc):
return partial(api.handleThread, days=days, perc=perc)
days = 5
return_perc = 10
api = externalApi()
process_item = process_item_generator(api, days, return_perc)
executor = ThreadPoolExecutor(max_workers=30)
responses = executor.map(process_item, (x.symbol for x in instruments))
return_response = ([x.symbol, x.name, response]
for x, response in zip(instruments, responses)
if response > float(return_perc))
这里我假设x.symbol
与x.trading_symbol
相同,我已经对你的API调用进行了虚拟实现,以获得某种类型的返回值,但它应该给出一个很好的想法这该怎么做。因此,代码有点长,但是再一次,它变成了一个可运行的例子。