一 分类
伪并发 由于执行速度很快,用户感知不到
真并发 同时发起并发
1 python调用的是操作系统的进程和线程,自身没有
2 一个应用程序默认只有一个进程(可以定义多个) 一个进程只有一个线程(可以定义多个)
二 线程
1 python的多线程分为主线程和其他线程.主进程会在多个线程进行来回切换处理
2 python的线程是工作的最小单元
3 python的线程共享进程中的所有资源
4 python无法利用多核CPU实现多线程的,因为有锁的存在,同一时间只能cpu调用一个线程
三 进程
1 独立开辟内存,能同时利用多核cpu
2 耗费资源单进程多线程的场景
3 如果主线程停止,那么所有子线程都要终止
四 第一种调用方式
threading模块
import threading
def func(args):
t=threading.current_thread()
print(t)
t1=threading.Thread(target=func函数,args=(11,))
t1.setDaemon(True)
t1.setname()
t1.start()
t1.join()
t2=threading.Thread(target=func函数,args=(11,))//子线程t2
t1.setDaemon(True)
t2.start()
t2.join()
五 第二种调用方式
import threading
class mythread(threading.Thread):// threading.Thread这里直接继承,省去了上面的第一步
def func(self,num):
print(num)
t1=mythread()
t1.func(11)
t2=mythread()
t2.func(123)
六 相关函数
1 threading.Thread(target=函数对象,args=参数)生成的对象调用以下
1 start():启动线程活动等待,cpu会调用.注意这里并不是表示线程的开始。
2 join([time]):
主线程A中,创建了子线程B,并且在主线程A中调用了B.join(),那么,主线程A会在调用的地方等待,直到子线程B完成操作后才可以接着往下执行,那么在调用这个线程时可以使用被调用线程的join方法。
join([timeout]) 里面的参数时可选的,代表线程运行的最大时间,即如果超过这个时间,不管这个此线程有没有执行完毕都会被回收,然后主线程或函数都会接着执行的,如果线程执行时间小于参数表示时间,则接着执行,不用一定要等待到参数表示的时间
参数的主要意义代表主线程不会无限等待子线程,设置子线程的超时回收
3 isAlive(): 返回线程是否活setDaemon()动的。
4 getName(): 返回线程名。
5 setName(): 设置线程名。
6 setDaemon()方法。主线程A中,创建了子线程B,并且在主线程A中调用了B.,这个的意思是,把主线程A设置为守护线程,这时候,要是主线程A执行结束了,就不管子线程B是否完成,一并和主线程A退出.这就是setDaemon方法的含义,这基本和join是相反的,根本不会等待子线程。此外,还有个要特别 注意的:必须在start() 方法调用之前设置,如果不设置为守护线程,程序会被无限挂起,只有等待了所有线程结束它才结束。
2 threading.event() 创建线程
3 threading.current_thread() 获取当前线程
七 python多线程的锁
GIL锁 全局解释器锁,用来限制同一个进程同一个时刻只有一个线程被cpu调用
在Python多线程下,每个线程的执行方式:
1、获取GIL
2、执行代码直到sleep或者是python虚拟机将其挂起。
3、释放GIL
可见,某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。而每次释放GIL锁,线程进行锁竞争、切换线程,会消耗资源。并且由于GIL锁存在,python里一个进程永远只能同时执行一个线程(拿到 GIL的线程才能执行),这就是为什么在多核CPU上,python的多线程效率并不高。
原文地址:https://www.cnblogs.com/danhuangpai/p/10949938.html