2017-07-24 170 views
0

想象我有这样一个功能:等待所有功能在返回值之前返回

def func1(): 
    return int(requests.get('https://www.random.org/integers/?num=1&min=0&max=10&col=1&base=10&format=plain&rnd=new').text) 

,我想调用这个函数三次,总结响应,然后返回平方的和或简单的东西。我该如何做到这一点,所以三个函数调用是异步的,但它等待他们都返回,一个Promise.all在Javascript中?

我使用Python 2

+1

为什么不能线程? –

+0

如果你使用的是Python 3,你可以使用它的异步特性...在Python 2中,你必须用[threading]来做(https://docs.python.org/2/library/threading.html) –

回答

1

你的目的,我修改功能位:

def func1(): 
    page = requests.get('https://www.random.org/integers/?num=1&min=0&max=10&col=1&base=10&format=plain&rnd=new').text 
    num = extract_num(page) # Any parsing function that extracts the number and converts it to an integer type. 
    cumulative += num # Sums up 

然后,使用线程:

import threading 

cumulative = 0 

for i in range(3): # Gets random numbers asynchronously. 
    threading.Thread(target=func1).start() 
print cumulative 
+0

我看到你在那里用全局变量做了什么,但我只是将随机数字作为可能需要可变时间的请求的一个例子,我并不特别在于总结随机数 – Rob

+1

您应该处理将您的线程加回到在打印累计结果之前的主线程。你也应该使用这个'cumulative'变量的互斥体,因为'cumulative + = num'不是原子操作。要查看这个问题,用''func1()''中的'num'替换为一个固定的数字(比如10),然后循环20次,然后看看它打印的是什么。另外'累计'必须被定义为全局的才能工作。 – zwer

+0

@Rob哦!但是上面定义的线程可以处理可变时间。他们不会做你想做的事吗? –

2

您需要使用为此,最简单的方法是通过multiprocessing.pool.ThreadPool包(不要让它欺骗你,尽管它处于包中但不是多处理):

import requests 
from multiprocessing.pool import ThreadPool 

# let's make it a bit more flexible 
RANDOM_URL = 'https://www.random.org/integers/' 
RANDOM_PARAMS = {"num": 1, "min": 0, "max": 10, "col": 1, "base": 10, 
       "format": "plain", "rnd": "new"} 

def func1(*args): # args added to account for the dummy payload from pool.map 
    return int(requests.get(RANDOM_URL, params=RANDOM_PARAMS).text) 

pool = ThreadPool(processes=3) 
response_sum = sum(pool.map(func1, range(3))) 
print("Squared response: {}".format(response_sum**2)) 
+0

只是好奇,我的答案和你的答案有任何性能差异吗?多线程在这个IO绑定用例中会更有效率还是多处理? –

+0

@SamChats - 正如我所说的,虽然'ThreadPool'在'multiprocessing.pool'包中,它根本不使用多处理 - 它只是围绕''threading'结构的便利包装,所以你没有自己将数据映射到线程,或者在线程完成处理后处理如何恢复数据。它的主要目的是作为模拟'多处理。Pool“主要用于测试/调试的原因,但对于这种情况非常有用。 – zwer

+0

很酷。这是否与'Queue'结构有关? –

0

取决于你的口味,如果你没事带安装第三方的反向移植模块https://pypi.python.org/pypi/futures你也可以使用concurrent.futures作为更高层次的接口,以避免处理线程,并且具有API更相似的承诺/期货你在你的问题中提到:

from concurrent.futures import ThreadPoolExecutor 
import requests 

def func1(): 
    return int(requests.get('https://www.random.org/integers/?num=1&min=0&max=10&col=1&base=10&format=plain&rnd=new').text) 

ex = ThreadPoolExecutor() 
f1 = ex.submit(func1) 
f2 = ex.submit(func1) 
f3 = ex.submit(func1) 

print(f1.result(), f2.result(), f3.result()) 
+0

引用OP“我正在使用Python 2.”,它也存在于问题的标签中。 'concurrent.futures.ThreadPoolExecutor'在Python 2中不可用。 – zwer

+0

我认为它也是2中的标准,很抱歉。事实证明,你必须安装一个backport模块来获取它在Python 2 https://pypi.python.org/pypi/futures –