当前位置: 首页 > 面试题库 >

如何在Python中的循环内对操作进行多线程

丁英韶
2023-03-14
问题内容

假设我的清单很大,并且正在执行如下操作:

for item in items:
    try:
        api.my_operation(item)
    except:
        print 'error with item'

我的问题有两个:

  • 有很多东西
  • api.my_operation需要永远返回

我想使用多线程一次启动一堆api.my_operations,以便我可以一次处理5或10甚至100个项目。

如果my_operation()返回一个异常(因为也许我已经处理过该项目),那就可以了。它不会破坏任何东西。循环可以继续到下一个项目。

注意 :这适用于Python 2.7.3


问题答案:

首先,在Python中,如果您的代码是CPU绑定的,那么多线程将无济于事,因为只有一个线程可以持有全局解释器锁,因此一次只能运行Python代码。因此,您需要使用进程,而不是线程。

如果您的操作“永远需要返回”是因为它是IO绑定的,也就是说,正在等待网络或磁盘副本等,这是不正确的。我稍后再讲。

接下来,一次处理5个或10个或100个项目的方法是创建5个或10个或100个工人的池,并将这些项目放入由工人服务的队列中。幸运的是,stdlibmultiprocessingconcurrent.futures库都为您包装了大多数细节。

前者在传统编程方面更强大,更灵活。如果您需要编写将来的等待,则后者更简单;对于微不足道的情况,选择哪一个并不重要。(在这种情况下,最明显的实现分别是带有3行,带有带有futures4行multiprocessing。)

如果您使用的是2.6-2.7或3.0-3.1,futures则不是内置的,但您可以从PyPI(pip install futures)安装它。

最后,如果您可以将整个循环迭代转换为函数调用(通常可以(例如,传递给map)),那么并行化处理通常会简单得多,所以让我们首先进行以​​下操作:

def try_my_operation(item):
    try:
        api.my_operation(item)
    except:
        print('error with item')

放在一起:

executor = concurrent.futures.ProcessPoolExecutor(10)
futures = [executor.submit(try_my_operation, item) for item in items]
concurrent.futures.wait(futures)

如果您有很多相对较小的工作,则多处理的开销可能会浪费收益。解决该问题的方法是将工作分批处理成更大的工作。例如(使用grouperitertools食谱,您可以复制并粘贴到你的代码,或者从一开始more- itertoolsPyPI上的项目):

def try_multiple_operations(items):
    for item in items:
        try:
            api.my_operation(item)
        except:
            print('error with item')

executor = concurrent.futures.ProcessPoolExecutor(10)
futures = [executor.submit(try_multiple_operations, group) 
           for group in grouper(5, items)]
concurrent.futures.wait(futures)

最后,如果您的代码受IO约束怎么办?这样线程就和进程一样好,并且开销更少(限制更少,但是在这种情况下这些限制通常不会影响您)。有时,“较少的开销”足以表示您不需要使用线程进行批处理,但是您需要使用进程,这是一个不错的选择。

那么,如何使用线程而不是进程?只需更改ProcessPoolExecutor为即可ThreadPoolExecutor

如果不确定代码是受CPU约束还是受IO约束,只需尝试两种方法即可。

我可以在python脚本中为多个功能执行此操作吗?例如,如果我想并行化的代码中其他地方有另一个for循环。是否可以在同一脚本中执行两个多线程函数?

是。实际上,有两种不同的方法可以做到这一点。

首先,您可以共享同一个(线程或进程)执行程序,并可以在多个地方使用它而没有问题。任务和未来的重点在于它们是独立的。您不在乎它们在哪里运行,只需将它们排队并最终得到答案即可。

另外,您可以在同一程序中有两个执行程序,这没有问题。这会降低性能,如果您同时使用两个执行器,最终将试图在8个内核上运行(例如)16个繁忙线程,这意味着将需要进行一些上下文切换。但是有时候值得这样做,因为例如两个执行者很少同时忙,这会使您的代码变得更简单。也许一个执行程序正在运行可能需要一段时间才能完成的非常大的任务,而另一个执行程序却正在运行需要尽快完成的非常小的任务,因为响应能力比部分程序的吞吐量更重要。

如果您不知道哪个适合您的程序,通常是第一个。



 类似资料:
  • 所以我正在编写代码,它将解析文件夹中的多个文本文件,收集它们的信息,并将这些信息保存在两个静态列表实例变量中。信息存放的顺序并不重要,因为我最终将对其进行排序。但由于某些原因,增加线程数不会影响速度。这是我的run方法和主方法中利用多线程的部分。 如果需要额外的信息,我基本上有一个静态实例变量作为我需要浏览的文件的数组,还有一个常量是线程数(为了测试目的手动更改)。如果我有4个线程和8个文件,每个

  • 我正在尝试创建一个自动打开我的在线类的脚本。我写了这样的代码: 现在,问题是第一个if语句被无休止地执行,我想让它只执行一次,而不是等到现在==lesson2再执行第二个if etc

  • 本文向大家介绍HashMap 多线程操作导致死循环问题?相关面试题,主要包含被问及HashMap 多线程操作导致死循环问题?时的应答技巧和注意事项,需要的朋友参考一下 主要原因在于 并发下的Rehash 会造成元素之间会形成一个循环链表。不过,jdk 1.8 后解决了这个问题,但是还是不建议在多线程下使用 HashMap,因为多线程下使用 HashMap 还是会存在其他问题比如数据丢失。并发环境下

  • 问题内容: 使用以下代码显示我的Twitter个人资料中的朋友列表。我想一次只加载一个特定的数字,例如20,然后在底部为第1-2-3-4-5页的页面提供分页链接(但是,除以限制) **更新**** 这项工作有效,只需要抵消从开始的输出即可。在想什么? 问题答案: 一个非常优雅的解决方案是使用:

  • 机器人必须每隔60秒做一件事。我尝试使用create_task,但它不起作用(bot启动了,但什么也没发生)。如何实现这一点?

  • 下面的代码片段执行两个线程,一个是每秒记录一次的简单计时器,第二个是执行remainder操作的无限循环: 这给出了以下结果: