线程
每个线程的执行时间不确定,线程是操作系统调度执行的最小单位.
线程的创建步骤
# 导入threading模块
import threading
# 创建一个线程对象
t1 = threading.Thread(target=func_name, args=(num,),name=”子线程名字”)
# 创建一个线程并启动
t1.start()
# 等待子线程执行完毕之后再继续向下执行主线程
t1.join()
备注:主线程会等待子线程结束之后才会结束,主线程一死,子线程也会死。线程的调度是随机的,并没有先后顺序
互斥锁的运用
由于多线程之间共享全局变量就会导致出现资源竞争的问题,为了避免这种竞争出现,利用互斥锁可以实现线程同步。
# 创建锁
Mutex = threading.Lock()
# 加锁
Mutex.acquire()
# 释放锁
Mutex.release()
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,尽管死锁很少发生,但一旦发生就会造成应用的停止响应.
超时时间解锁:
# 加锁时加超时时间
Mutex.acquire(timeout=1)
threading模块的对象
对象 | 描述 |
---|---|
Thread | 表示一个执行线程的对象 |
Lock | 锁原语对象 |
RLock | 可重入锁对象,使单一线程可以(再次)获得已持有的锁(递归锁) |
… | …待添加… |
Thread类
Thread对象方法 | 描述 |
---|---|
init(group=None,tatget=None,name=None,args=(),kwargs={},verbose=None,daemon=None) | 实例化一个线程对象,需要有一个可调用的target,以及其参数args或kwargs |
star() | 开始执行线程 |
run | 定义线程功能的方法(通常在子类中被应用开发者重写) |
join(timeout=None) | 直至启动的线程终止前一直挂起,除非给了超时,否则一直阻塞 |
进程
进程的创建步骤
# 导入进程模块
import multiprocessing
# 创建一个进程的实例对象
p = multiprocessing.Process(target=fun_name,args=(元组),kwargs={字典})
# 创建并启动进程
p.start()
p.join() 可以阻塞主进程,等待子进程的结束
# 获取进程的pid
os.getpid()
# 获取进程的父进程的pid
os.getppid()
**进程中,主进程的父进程pid是系统产生的,子进程的父进程pid是主进程的pid,
主进程死掉,子进程不会死,子进程会有新的父进程,(这个进程的名字好像是upstart)如果继续kill掉这个进程,将锁屏。
通过Queue实现进程间通信
# 创建一个队列
q = multiprocessing.Queue(5) # 5代表队列可以接受的容量
# 向队列添加数据
q.put(data)
# 从队列中获取数据
q.get()
# 判断队列是否为空,为空返回True
q.empty()
# 判断队列中是否已满
q.full()
**注意:如果是通过进程池创建的进程,那么队列的使用要用 multiprocessing.Manager().Queue()的方式,否则会报错。**
进程池Pool
# 导入进程池模块
from multiprocessing import Pool
# 定义进程池,最大进程数
po = Pool(3)
# 通过进程池调用目标 apply_async 非阻塞,不会等待子进程结束,apply 阻塞,会等待子进程结束才结束
po.apply_async(要调用的目标,(传递给目标的参数元组,))
# 关闭进程池
po.close()
# 等待进程池执行完毕
po.join()
协程
协程,又称微线程,纤程。利用线程在等待某个资源的期间执行其他函数,切换资源消耗非常小,协程效率相当快。
进程、线程、协程的区别
1. 进程是资源分配的单位
2. 线程是操作系统调度的单位
3. 进程切换需要的资源很最大,效率很低
4. 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
5. 协程切换任务资源很小,效率高
6. 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发
7. 协程依赖于线程,线程依赖于进程,进程一死线程必挂,线程一死协程必死。
gevent
import gevent
def f(n):
for i in range(n):
print(gevent.getcurrent(), i)
#用来模拟一个耗时操作,注意不是time模块中的sleep
gevent.sleep(1)
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
并发下载器
from gevent import monkey
import gevent
import urllib.request
# 有耗时操作是需要,打补丁
monkey.patch_all()
def my_download(name,url):
# 请求
resp = urllib.request.urlopen(url)
data = respl.read()
# 保存数据
with open(name,"wb") as f:
f.write(data)
def main():
gevent.joinall([ gevent.spawn(my_download, "1.jpg", "https://img02.sogoucdn.com/app/a/100520024/8eb2dc17fb6a6a87ae12aeb319dfc239")) ])
if __name__ == "__main__":
main()