参考文献:https://gitee.com/wupeiqi/python_course
并发编程:提升代码执行的效率。原来需要 10 分钟执行,并发处理后可以加快到 1 分钟。
初识进程和线程
多线程开发
线程安全
线程锁
1.进程和线程: 线程,是计算机中可以被cpu调度的最小单元(真正在工作)。 进程,是计算机资源分配的最小单元(进程为线程提供资源)。 一个进程中可以有多个线程,同一个进程中的线程可以共享此进程中的资源。以前我们开发的程序中所有的行为都只能通过串行的形式运行,排队逐一执行,前面未完成,后面也无法继续。例如:
import time result = 0 for i in range(100000000): result += i print(result) import time import requests url_list = [ ("东北F4模仿秀.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0300f570000bvbmace0gvch7lo53oog"), ("卡特扣篮.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f3e0000bv52fpn5t6p007e34q1g"), ("罗斯mvp.mp4", "https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg") ] print(time.time()) for file_name, url in url_list: res = requests.get(url) with open(file_name, mode=\'wb\') as f: f.write(res.content) print(file_name, time.time())通过 进程 和 线程 都可以将 串行 的程序变为并发,对于上述示例来说就是同时下载三个视频,这样很短的时间内就可以下载完成。
1.1 GIL锁GIL, 全局解释器锁(Global Interpreter Lock),是CPython解释器特有一个玩意,让一个进程中同一个时刻只能有一个线程可以被CPU调用。
如果程序想利用 计算机的多核优势,让CPU同时处理一些任务,适合用多进程开发(即使资源开销大)。
如果程序不利用 计算机的多核优势,适合用多线程开发。
常见的程序开发中,计算操作需要使用CPU多核优势,IO操作不需要利用CPU的多核优势,所以,就有这一句话:
计算密集型,用多进程,例如:大量的数据计算【累加计算示例】。
IO密集型,用多线程,例如:文件读写、网络数据传输【下载抖音视频示例】。
累加计算示例(计算密集型):
串行处理
import time start = time.time() result = 0 for i in range(100000000): result += i print(result) end = time.time() print("耗时:", end - start) # 耗时: 9.522780179977417
多进程处理
import time import multiprocessing def task(start, end, queue): result = 0 for i in range(start, end): result += i queue.put(result) if __name__ == \'__main__\': queue = multiprocessing.Queue() start_time = time.time() p1 = multiprocessing.Process(target=task, args=(0, 50000000, queue)) p1.start() p2 = multiprocessing.Process(target=task, args=(50000000, 100000000, queue)) p2.start() v1 = queue.get(block=True) #阻塞 v2 = queue.get(block=True) #阻塞 print(v1 + v2) end_time = time.time() print("耗时:", end_time - start_time) # 耗时: 2.6232550144195557当然,在程序开发中 多线程 和 多进程 是可以结合使用,例如:创建2个进程(建议与CPU个数相同),每个进程中创建3个线程。
import multiprocessing import threading def thread_task(): pass def task(start, end): t1 = threading.Thread(target=thread_task) t1.start() t2 = threading.Thread(target=thread_task) t2.start() t3 = threading.Thread(target=thread_task) t3.start() if __name__ == \'__main__\': p1 = multiprocessing.Process(target=task, args=(0, 50000000)) p1.start() p2 = multiprocessing.Process(target=task, args=(50000000, 100000000)) p2.start() 2.多线程开发 import threading def task(arg): print(arg) # 创建一个Thread对象(线程), 并封装线程被CPU 调度时应该执行的任务和相关参数。 t=threading.Thread(target=task,args=(\'xxx\',))# 注意此处函数的后面不需要添加() \'\'\'当元组只有一个元素时需要添加一个额外的逗号,表示是数据类型是元组\'\'\' # 线程准备就绪等待被CPU调度,代码继续向下执行 t.start() print("继续执行。。。。")线程的常见方法:
t.start(),当前线程准备就绪(等待CPU调度,具体时间是由CPU来决定)。
import threading loop = 10000000 number = 0 def _add(count): global number for i in range(count): number += 1 t = threading.Thread(target=_add,args=(loop,)) t.start() print(number)