【问题标题】:Python: Serial, Threading, Multiprocessing. Which is the fastest way?Python:串行、线程、多处理。哪种方式最快?
【发布时间】:2021-02-11 03:05:28
【问题描述】:

所以我有一个代码需要执行 HTTP 请求(比如说 1000)。到目前为止,我用 3 种方式处理了 50 个 HTTP 请求。结果和代码如下。

最快的是使用线程的方法,问题是我丢失了一些数据(根据我对 GIL 的理解)。我的问题如下:

  1. 我的理解是,在这种情况下,正确的方法是使用多处理。有什么办法可以提高这种方法的速度吗?匹配线程时间会很棒。

  2. 我猜我拥有的链接数量越多,串行和线程方法所花费的时间就越多,而多处理方法的增长速度会慢得多。您是否有任何来源可以让我估算出运行带有 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


【解决方案1】:

如果我要提出任何建议,我会选择AIOHTTP。代码草图:

import aiohttp
import asyncio

async def main(alink):
    links = [link_1, link_2, ..., link_n]
    matrix = []

    async with aiohttp.ClientSession() as session:
        async with session.get(alink) as resp:
            return resp.data()


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    
    for link in links:
        loop.run_until_complete(main(link))

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多