摘要:也提供多线程支持,而且中的线程并非是模拟出来的多线程,而是系统级别的标准库提供了两个模块和。同一个变量,线程则会互相共享。例如多个线程对银行中的某一个账户进行操作。但是实际情况是随意切换线程。说到的多线程编程,就会绕不过。
该文章参考了http://www.liaoxuefeng.com/wi... 廖雪峰的教程。
一个进程至少有一个线程。
Python也提供多线程支持,而且Python中的线程并非是模拟出来的多线程,而是系统级别的Posix Thread.
Python标准库提供了两个模块thread和threading。前者是低级库,后者是高级库。高级库是对低级库的封装。
通常情况下,我们只需要使用threading高级库就可以了。
我们只需要创建threading.Thread类,并传入一个需要线程执行的函数作为target即可。
import threading import time def loop(): count = 1 while count < 4: print "Hello" time.sleep(1) count += 1 if __name__ == "__main__": thread = threading.Thread(target=loop, name="LoopThread") thread.start() thread.join() current_thread = threading.current_thread() print current_thread.getName() print "LoopThread Ended"
上述代码主进程默认会创建一个主线程。
上面的代码中,我们用到了多个函数。
join()函数:即让主线程序等待子线程完成后继续。
current_thread()函数:获取当前线程的实例。
Lock 锁同一个变量,进程会拷贝一份存于各个进程中,互不影响。
同一个变量,线程则会互相共享。这就会带来一些问题。因为cpu对线程是随意切换的。那么如果一个线程对某一个变量进行多步cpu操作的时候,如果不加锁,那么可能会在线程进行到一半的时候,会被切换到其他线程,从而使得操作变乱。
一个典型的例子是“一存一取”的场景。
例如多个线程对银行中的某一个账户进行操作。一个线程需要对账户进行一存一取某一个金额的操作才会让账户平衡。
但是多个线程对该账户进行操作的时候,且它们操作的金额经常是不一样的,那么最终的账户很可能是不平衡的。
thread 1: -100 thread 1: +100 thread 1: -100 thread 1: +100 thread 2: -200 thread 2: +200 thread 2: -200 thread 2: +200
上述描述了两个线程按顺序互补干扰地对某一个账户进行操作。
但是实际情况是cpu随意切换线程。上述操作是打乱的,例如
thread 1: -100 thread 2: -200 thread 2: +200 ...
此时,我们发现账户并不是平衡的。
如果解决呢?我们需要对每一个thread的一存一取操作加一把锁。即改账户变量必须是让一个线程先进行完整的一存一取操作后,才能被其他线程所操作。
我们可以将要上锁的代码包裹起来,即:
lock.acquire() num = num + n num = num - n print num lock.release()
当然,lock可以对资源的获取和释放,那么我们也可以用with关键字。
with lock: num = num + n num = num - n print num死锁 deadlock
死锁的发生往往是两个线程各自占用了对方所需要用到的资源而都在等待对方释放资源而造成的。
遇见死锁后,程序则会一直暂停在那里。直到系统将它们关闭。
说到Python的多线程编程,就会绕不过GIL。那么GIL又是什么鬼呢?
GIL据说是Python中hardest的问题,想要彻底了解GIL,必须要对操作系统设计、多线程编程、C语言、解释器设计和CPython解释器的实现有着非常彻底的理解。
据廖雪峰中的教程中描述:
Python中的线程虽然是真正的线程,但是解释器执行代码的时候,会有一个GIL锁(Global Interpreter Lock). 任何Python线程执行前,必须先获得GIL锁。然后,每执行100条字节码,解释器就会自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁。因此,多线程在Python中只能交替进行,即使100个线程跑在100核CPU上,也只能用到1个核心。
GIL是Python解释器设计的历史遗留问题,通常我们用的解释器是官方实现彻底CPython。
更多关于GIL设计的历史渊源,可以阅读:
http://cenalulu.github.io/pyt...
http://www.oschina.net/transl...
那么是不是Python就是不能利用多核处理器任务了呢?我们之前学到过多进程编程,每一个进程都有一个独立的GIL锁,各进程互不影响。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/38366.html
摘要:试想,在多线程服务器中,多个线程同时处理不同客户端发送的不同请求时,每个线程看到的对象必然不同。多线程服务器会创建一个线程池,再从线程池中选择一个线程用于处理接收到的请求。 框架 Django flask flask是一个轻量的web开发应用示例开发一个小应用 from flask import Flask app = Flask(__name__) @app.route(/) d...
摘要:为了避免改乱为,我们在前面已经提到说要加锁。仅供一个线程使用,线程间相互不影响。例如下列程序中函数中定义的变量就是局部变量。所有绑定的参数都是线程隔离的。下面展示一下代码创建一个全局的对象初始化一个线程内变量,该变量线程间互不影响。 我们在编写多线程程序的时候,往往会遇到两种类型的变量。 一种是全局变量,多个线程共享。为了避免改乱为,我们在前面已经提到说要加锁。 一种是局部变量。仅供...
摘要:首发于我的博客线程池进程池网络编程之同步异步阻塞非阻塞后端掘金本文为作者原创,转载请先与作者联系。在了解的数据结构时,容器可迭代对象迭代器使用进行并发编程篇二掘金我们今天继续深入学习。 Python 算法实战系列之栈 - 后端 - 掘金原文出处: 安生 栈(stack)又称之为堆栈是一个特殊的有序表,其插入和删除操作都在栈顶进行操作,并且按照先进后出,后进先出的规则进行运作。 如...
摘要:开头正式开启我入职的里程,现在已是工作了一个星期了,这个星期算是我入职的过渡期,算是知道了学校生活和工作的差距了,总之,尽快习惯这种生活吧。当时是看的廖雪峰的博客自己也用做爬虫写过几篇博客,不过有些是在前人的基础上写的。 showImg(https://segmentfault.com/img/remote/1460000010867984); 开头 2017.08.21 正式开启我...
阅读 3404·2021-11-25 09:43
阅读 2580·2021-09-22 15:54
阅读 571·2019-08-30 15:55
阅读 941·2019-08-30 15:55
阅读 1978·2019-08-30 15:55
阅读 1723·2019-08-30 15:53
阅读 3446·2019-08-30 15:52
阅读 2024·2019-08-30 12:55