目录
Python并发编程04/多线程
1.生产消费者模型
#编程思想,模型,设计模式,理论等等,都是交给你一种编程的方法,以后你遇到类似的情况,套用即可.生产者消费者模型三要素:# 生产者: 产生数据的# 消费者: 接收数据做进一步处理的# 容器: 盆(队列)队列容器的作用:#起到缓冲的作用,平衡生产力与消费力,解耦.# from multiprocessing import Process# from multiprocessing import Queue# import time# import random## def producer(q,name):# for i in range(1,6):# time.sleep(random.randint(1,2))# res = f'{i}号包子'# q.put(res)# print(f'生产者{name} 生产了{res}')### def consumer(q,name):# while 1:# try:# food = q.get(timeout=3)# time.sleep(random.randint(1, 3))# print(f'\033[31;0m消费者{name} 吃了{food}\033[0m')# except Exception:# return## if __name__ == '__main__':# q = Queue()# p1 = Process(target=producer,args=(q,'小白'))# p2 = Process(target=consumer,args=(q,'小黑'))# p1.start()# p2.start()
2.线程的理论知识
2.1什么是线程
#一条流水线的工作流程.#进程: 在内存中开启一个进程空间,然后将主进程的所有的资源数据复制一份,然后调用cpu去执行这些代码.#之前的描述不够具体:#开启一个进程: #在内存中开启一个进程空间,然后将主进程的所有的资源数据复制一份,然后调用线程去执行代码***进程是资源单位, 线程是执行单位.标准描述开启一个进程: 开启一个进程:进程会在内存中开辟一个进程空间,将主进程的资料数据全部复制一份,线程会执行里面的代码.
2.2线程vs进程
#1. 开启进程的开销非常大,比开启线程的开销大很多.#2. 开启线程的速度非常快.要快几十倍到上百倍.#3. 同一进程线程与线程之间可以共享数据,进程与进程之间需借助队列等方法实现通信.
2.3线程的应用
#1. 并发: 一个cpu 看起来像是同时执行多个任务.# 单个进程开启三个线程.并发的执行任务.# 开启三个进程并发的执行任务.# 文本编辑器:# 1. 输入文字.# 2. 在屏幕上显示.# 3. 保存在磁盘中.## 开启多线程就非常好了: # 数据共享, 开销小,速度快.#主线程子线程没有地位之分,但是,一个进程谁在干活? 一个主线程在干活,当干完活了,你得等待其他线程干完活之后,才能结束本进程.
3.开启进程的两种方式
3.1第一种方式
# from threading import Thread# import time## def task(name):# print(f'{name} is running')# time.sleep(1)# print(f'{name} is gone')## if __name__ == '__main__':## t1 = Thread(target=task,args=('二狗',))# t1.start()# print('===主线程') # 线程是没有主次之分的.
3.2第一种方式
# from threading import Thread# import time## class MyThread(Thread):## def __init__(self,name,l1,s1):# super().__init__()# self.name = name# self.l1 = l1# self.s1 = s1# def run(self):# print(f'{self.name} is running')# time.sleep(1)# print(f'{self.name} is gone')## if __name__ == '__main__':# t1 = MyThread('二狗', [1,2,3], '180')# t1.start()# print('=====主线程')
4.线程vs进程的代码对比
4.1开启速度对比
多进程
# from threading import Thread# from multiprocessing import Process# import os## def work():# print('hello')## if __name__ == '__main__':# #在主进程下开启线程# t=Process(target=work)# t.start()# print('主线程/主进程')
多线程
# from threading import Thread# import time## def task(name):# print(f'{name} is running')# time.sleep(1)# print(f'{name} is gone')### if __name__ == '__main__':## t1 = Thread(target=task,args=('二狗',))# t1.start()# print('===主线程') # 线程是没有主次之分的.
4.2对比pid
进程
# from multiprocessing import Process# import time# import os# def task(name):# print(f'子进程: {os.getpid()}')# print(f'主进程: {os.getppid()}')## if __name__ == '__main__':## p1 = Process(target=task,args=('二狗',)) # 创建一个进程对象# p2 = Process(target=task,args=('二狗',)) # 创建一个进程对象# p1.start()# p2.start()# print(f'==主{os.getpid()}')
线程
# from threading import Thread# import os## def task():# print(os.getpid())## if __name__ == '__main__':## t1 = Thread(target=task)# t2 = Thread(target=task)# t1.start()# t2.start()# print(f'===主线程{os.getpid()}')
4.3同一个进程内线程共享内部数据
# from threading import Thread# import os## x = 3# def task():# global x# x = 100## if __name__ == '__main__':## t1 = Thread(target=task)# t1.start()# t1.join()# print(f'===主线程{x}')同一进程内的资源数据对于这个进程的多个线程来说是共享的.
5.线程的其他方法
# from threading import Thread# from threading import currentThread# from threading import enumerate# from threading import activeCount# import os# import time## def task():# # print(currentThread())# time.sleep(1)# print('666')# if __name__ == '__main__':## t1 = Thread(target=task,name='线程1')# t2 = Thread(target=task,name='线程2')# # name 设置线程名# t1.start()# t2.start()# # time.sleep(2)# # print(t1.isAlive()) # 判断线程是否活着# # print(t1.getName()) # 获取线程名# # t1.setName('子线程-1')# # print(t1.name) # 获取线程名 ***## # threading方法# # print(currentThread()) # 获取当前线程的对象# # print(enumerate()) # 返回一个列表,包含所有的线程对象# print(activeCount()) # ***# print(f'===主线程{os.getpid()}')
6.join与守护线程
6.1join
join: 阻塞 告知主线程要等待我子线程执行完毕之后再执行主线程# from threading import Thread# import time## def task(name):# print(f'{name} is running')# time.sleep(1)# print(f'{name} is gone')## if __name__ == '__main__':# start_time = time.time()# t1 = Thread(target=task,args=('二狗',))# t2 = Thread(target=task,args=('二狗1',))# t3 = Thread(target=task,args=('二狗2',))## t1.start()# t1.join()# t2.start()# t2.join()# t3.start()# t3.join()## print(f'===主线程{time.time() - start_time}') # 线程是没有主次之分的.
6.2守护线程
# from threading import Thread# import time## def sayhi(name):# print('你好!')# time.sleep(2)# print('%s say hello' %name)## if __name__ == '__main__':# t = Thread(target=sayhi,args=('egon',))# # t.setDaemon(True) #必须在t.start()之前设置# t.daemon = True# t.start() # 线程的开启速度要跟进程开很多## print('主线程')
# from threading import Thread# import time## def foo():# print(123) # 1# time.sleep(1)# print("end123") # 4## def bar():# print(456) # 2# time.sleep(3)# print("end456") # 5## t1=Thread(target=foo)# t2=Thread(target=bar)## t1.daemon=True# t1.start()# t2.start()# print("main-------") # 3结果:123456main-------end123end456
守护线程 等待非守护子线程以及主线程结束之后,结束.# from threading import Thread# import time## def foo():# print(123) # 1# time.sleep(3)# print("end123") # 4## def bar():# print(456) # 2# time.sleep(1)# print("end456") # 5## t1=Thread(target=foo)# t2=Thread(target=bar)## t1.daemon=True# t1.start()# t2.start()# print("main-------") # 3
7.互斥锁
# from threading import Thread# import time# import random# x = 100## def task():# global x# temp = x# time.sleep(random.randint(1, 3))# temp = temp - 1# x = temp### if __name__ == '__main__':# l1 = []# for i in range(100):# t = Thread(target=task)# l1.append(t)# t.start()## for i in l1:# i.join()# print(f'主线程{x}')
多个任务公抢一个数据,保证数据的安全的目的,要让其串行# from threading import Thread# from threading import Lock# import time# import random# x = 100## def task(lock):## lock.acquire()# # time.sleep(random.randint(1,2))# global x# temp = x# time.sleep(0.01)# temp = temp - 1# x = temp# lock.release()### if __name__ == '__main__':# mutex = Lock()# l1 = []# for i in range(100):# t = Thread(target=task,args=(mutex,))# l1.append(t)# t.start()## for i in l1:# i.join()# print(f'主线程{x}')