Python并发复习1 - 多线程
2018-10-29 15:30:40来源:博客园 阅读 ()
一、基本概念
程序: 指令集,静态,
进程: 当程序运行时,会创建进程,是操作系统资源分配的基本单位
线程: 进程的基本执行单元,每个进程至少包含一个线程,是任务调度和执行的基本单位
> 进程和线程之间的关系:
① 一个线程只属于一个进程
② 一个进程可以包含多个线程,只有一个主线程
> 进程和线程资源对比① 进程具有独立的空间和系统资源
② 线程不具有独立的空间和系统资源
③ 同一个进程下的多个线程共享该进程的空间和系统资源
④ 局部变量不共享
> 多线程中对于贡献资源修改的问题
--- 多线程的同步问题、 线程不安全、通过同步解决
二、 多线程
1.需要清楚的一点
单核CPU: 宏观并行,微观实际上是串行 - 并发
多核CPU: 微观本质并行
2.应用场合:
① 计算密集型 --- 不适合单核CPU多线程 --- 数值计算
② I/O密集型 --- 适合单核CPU多线程 --- 频繁读写
3.优点:
速度快
4.缺点:
(1) 线程本身也是程序,线程越多,占用的内存越多;
(2) 多线程的调用需要协调管理,CPU对线程的跟踪需要消耗内存;
(3) CPU多线程的切换需要消耗内存
(4) 多线程之间对共享资源问题,需要解决数据的一致性
三、 线程的创建
三种方式:
(1) threading模块
--- 通过指定target(函数名)和args(函数参数)
(2) 使用Thread类,重写run方法
(3) 使用线程池
3.1 threading模块
1 import threading 2 import time 3 def misson(*args): 4 for i in range(args[1]): 5 print(i) 6 time.sleep(1) 7 # 创建线程对象,参数必须使用元组传递 8 t = threading.Thread(target = mission, args = args) 9 # 激活线程(排队),等待CPU分配时间片来执行 10 t.start() 11 t.start()
3.2. 使用Thread类,重写run方法
--- 适用于需要创建很多个执行方法相同的线程对象时,用类方法
1 class My_Thread(threading.Thread): 2 def __init__(self, n1): 3 self.n1 = n1 4 super().__init__() 5 # run方法是真正执行函数认为的方法 6 def run(self): 7 for i in range(self.end): 8 print(i) 9 t1 = My_Thread() 10 t1.start(10)
3.3 线程池
线程池的使用threadpool较少,使用concurrent.futures下的 ThreadPoolExecutor 线程池
1 from concurrent.futures import ThreadPoolExecutor 2 import time 3 4 5 def sayhello(a): 6 print("hello: " + a) 7 time.sleep(2) 8 9 10 def main(): 11 seed = ["a", "b", "c"] 12 13 # 第一种方法submit 14 with ThreadPoolExecutor(3) as executor: 15 for each in seed: 16 executor.submit(sayhello, each) 17 18 # 第二种方法map 19 with ThreadPoolExecutor(3) as executor1: 20 executor1.map(sayhello, seed) 21 22 23 if __name__ == '__main__': 24 main()
四、 线程的生命周期
(1) 新建 --- 创建线程对象,没有执行能力
(2) 就绪 --- 调用start方法,把执行权利交给CPU
(3) 运行 --- 执行线程任务,获得CPU时间片在一个线程运行时,可能将时间片分配给其他线程
(4) 阻塞 --- 处于等待过程,CPU不给阻塞状态分配时间片
(5) 死亡 --- run方法执行完毕或者抛出没有捕获的异常
五、线程的同步
--- 在同一个进程下,各个线程共享资源引起不安全,即对成员变量的操作进行共享
1. 抢票问题 - 锁
1 import time 2 import threading 3 4 ticket = 100 5 6 def buy_ticket(): 7 global ticket 8 while ticket: 9 t = threading.current_thread() 10 print(f'{t.name}{ticket}') 11 time.sleep(0.5) 12 ticket -= 1 13 14 if __name__ == '__main__': 15 t1 = threading.Thread(target=buy_ticket) 16 t1.name = '张三' # 设定线程名字 17 t1.start() 18 t2 = threading.Thread(target=buy_ticket) 19 t2.name = '张四' 20 t2.start() 21 t3 = threading.Thread(target=buy_ticket) 22 t3.name = '张五' 23 t3.start()
运行结果如下,会出现重复的抢票,即多个线程获得同一个变量:
解决办法:
使用线程锁, 即在同一时间内,一个共享资源只能被一个线程访问
加锁 --- threading.Lock()
抢锁 --- lock.acquare()
解锁 --- lock.release()
1 import time 2 import threading 3 4 lock = threading.Lock() 5 ticket = 100 6 def buy_ticket(): 7 global ticket 8 while True: 9 try: 10 lock.acquire() 11 if ticket > 0: 12 t = threading.current_thread() 13 time.sleep(0.2) 14 print(f'{t.name}抢到了第{ticket}张票') 15 ticket -= 1 16 else: 17 break 18 finally: 19 lock.release() 20 21 t1=threading.Thread(target=buy_ticket) 22 t1.name="张三" 23 t2=threading.Thread(target=buy_ticket) 24 t2.name="李四" 25 t3=threading.Thread(target=buy_ticket) 26 t3.name="王五" 27 28 t1.start() 29 t2.start() 30 t3.start()
2. 生产者消费者模型
(1) 消费者一直消费,商品=0,等待生产 --- wait
(2) 生产者隔一段时间看一次,如果小于3,开始生产 --- 耗费CPU
(3) 只要消费者消费了产品,通知生产者生产商品 --- notify
程序见Python并发复习2 - threading模块
六、多进程
1. 进程创建
(1)使用multiprocessing.Process(target=函数名)
(2)继承Process重写run
2. 进程操作
Os.getpid # 得到本身进程id
Os.getppid # 得到父进程id
Fork:复制进程,只能在linux下使用
其他方法同线程
3. 进程队列
进程优于线程:
不存在资源共享问题,没有同步锁,也没有死锁
多进程需要处理资源共享问题,使用队列序列化处理(进程队列已经处理好)
程序见Python并发复习2 - threading模块
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- python3基础之“术语表(2)” 2019-08-13
- python3 之 字符串编码小结(Unicode、utf-8、gbk、gb2312等 2019-08-13
- Python3安装impala 2019-08-13
- 小白如何入门 Python 爬虫? 2019-08-13
- python_字符串方法 2019-08-13
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash