【发布时间】:2021-02-11 03:05:28
【问题描述】:
所以我有一个代码需要执行 HTTP 请求(比如说 1000)。到目前为止,我用 3 种方式处理了 50 个 HTTP 请求。结果和代码如下。
最快的是使用线程的方法,问题是我丢失了一些数据(根据我对 GIL 的理解)。我的问题如下:
-
我的理解是,在这种情况下,正确的方法是使用多处理。有什么办法可以提高这种方法的速度吗?匹配线程时间会很棒。
-
我猜我拥有的链接数量越多,串行和线程方法所花费的时间就越多,而多处理方法的增长速度会慢得多。您是否有任何来源可以让我估算出运行带有 n 个链接的代码所需的时间?
串行 - 运行时间大约 10 秒
def get_data(link, **kwargs):
data = requests.get(link)
if "queue" in kwargs and isinstance(kwargs["queue"], queue.Queue):
kwargs["queue"].put(data)
else:
return data
links = [link_1, link_2, ..., link_n]
matrix = []
for link in links:
matrix.append(get_data(link))
线程 - 运行时间约为 0.8 秒
def get_data_thread(links):
q = queue.Queue()
for link in links:
data = threading.Thread(target = get_data, args = (link, ), kwargs = {"queue" : q})
data.start()
data.join()
return q
matrix = []
q = get_data_thread(links)
while not q.empty():
matrix.append(q.get())
多处理 - 运行时间约为 5 秒
def get_data_pool(links):
p = mp.Pool()
data = p.map(get_data, links)
return data
if __name__ == "__main__":
matrix = get_data_pool(links)
【问题讨论】:
-
我对这些测试持怀疑态度。 “线程”版本实际上只是在生成下一个之前为 each 链接运行一个新线程以完成,因此它实际上是一个带有启动/加入线程开销的串行测试。我很难相信它比串行版本快一个数量级以上。
-
@bnaecker,我不认为是这样,因为在发送请求和接收响应之间的时间内,另一个线程可以运行。问题是(从我在线阅读的内容),多个线程可以尝试同时访问队列,导致数据丢失
-
不,另一个线程无法运行。您拨打
data.start(),然后立即拨打data.join()。第二次调用 blocks 直到引用的线程完成(即,get_data返回)。您一次最多运行一个线程。不,多个线程不能同时访问队列。标准库queue.Queue对象在设计上是线程安全的。如果您丢失数据,那是因为您的代码中存在其他错误,例如未正确处理错误。 -
对不起,编辑了代码,我在这里粘贴不正确,.join() 在循环之外。对我来说,这个问题与stackoverflow.com/questions/11464750/… 的问题相同,此外,如果您查看本教程,第 8 分钟,在我看来与我所做的相同实现 youtube.com/watch?v=cdPZ1pJACMI 我尝试多次运行代码。串行需要 10 - 12 秒,线程需要 0.8 - 1.2 秒,但会丢失 10% - 20% 的值。不知道为什么在这一点上,如果你说我的解释不正确
-
在您的线程示例中,您每次在 for 循环中都用一个新值覆盖
data- 因此该线程至多是孤立的,只留下最后一个。将它们附加到 for 循环中的列表,然后您可以稍后迭代列表joining 他们。
标签: python python-3.x multithreading multiprocessing