我对多线程是否适用于 Python 有点困惑。
我知道有很多关于这个的问题,我已经阅读了很多,但我仍然感到困惑。我从自己的经验中知道,并且看到其他人在 StackOverflow 上发布了他们自己的答案和示例,多线程在 Python 中确实是可能的。那么为什么大家一直说 Python 被 GIL 锁住了,一次只能运行一个线程呢?它显然确实有效。还是有一些我没有在这里得到的区别?
许多发帖人/受访者还不断提到线程是有限的,因为它不使用多个内核。但我会说它们仍然很有用,因为它们确实同时工作,因此可以更快地完成组合工作量。我的意思是为什么还要有一个 Python 线程模块?
更新:
感谢到目前为止的所有答案。我的理解是多线程只会并行运行一些 IO 任务,但对于 CPU 绑定(bind)的多核任务一次只能运行一个。
我不完全确定这对我来说实际上意味着什么,所以我只举一个我想多线程执行的任务的例子。例如,假设我想遍历一个很长的字符串列表,并且我想对每个列表项进行一些基本的字符串操作。如果我拆分列表,将每个子列表发送给我的循环/字符串代码在一个新线程中处理,然后将结果发送回队列中,这些工作负载会大致同时运行吗?最重要的是,这在理论上会加快运行脚本所需的时间吗?
另一个例子是,如果我可以在四个不同的线程中使用 PIL 渲染和保存四张不同的图片,这是否比一张一张地处理图片更快?我想这个速度组件才是我真正想知道的,而不是正确的术语是什么。
我也知道多处理模块,但我现在的主要兴趣是中小型任务负载(10-30 秒),所以我认为多线程会更合适,因为子进程启动速度可能很慢。
最佳答案
GIL 不会阻止线程化。 GIL 所做的只是确保一次只有一个线程在执行 Python 代码;控制仍然在线程之间切换。
GIL 阻止的是使用多个 CPU 内核或单独的 CPU 来并行运行线程。
这仅适用于 Python 代码。 C 扩展可以并且确实释放 GIL 以允许 C 代码的多个线程和一个 Python 线程跨多个内核运行。这扩展到由内核控制的 I/O,例如对套接字读取和写入的 select() 调用,使 Python 在多线程多核设置中合理有效地处理网络事件。
然后,许多服务器部署会运行多个 Python 进程,让操作系统处理进程之间的调度,以最大限度地利用 CPU 内核。您也可以使用 multiprocessing library处理来自一个代码库和父进程的多个进程的并行处理,如果这适合您的用例。
请注意,GIL 仅适用于 CPython 实现; Jython 和 IronPython 使用不同的线程实现(分别是原生 Java VM 和 .NET 公共(public)运行时线程)。
直接解决您的更新:任何尝试使用纯 Python 代码从并行执行中获得速度提升的任务都不会看到速度提升,因为线程化 Python 代码一次锁定到一个线程执行。但是,如果您混合使用 C 扩展和 I/O(例如 PIL 或 numpy 操作)并且任何 C 代码都可以与 一个 事件 Python 线程并行运行。
Python 线程非常适合创建响应式 GUI,或用于处理 I/O 比 Python 代码更成为瓶颈的多个短 Web 请求。它不适合并行计算密集型 Python 代码,坚持使用 multiprocessing 模块执行此类任务或委托(delegate)给专用的外部库。
关于python - Python 支持多线程吗?它可以加快执行时间吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20939299/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试