目录
-
Python并发编程04/多线程
- 1.生产消费者模型
-
2.线程的理论知识
- 2.1什么是线程
- 2.2线程vs进程
- 2.3线程的应用
-
3.开启进程的两种方式
- 3.1第一种方式
- 3.2第一种方式
-
4.线程vs进程的代码对比
- 4.1开启速度对比
- 4.2对比pid
- 4.3同一个进程内线程共享内部数据
- 5.线程的其他方法
-
6.join与守护线程
- 6.1join
- 6.2守护线程
- 7.互斥锁
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
结果:
123
456
main-------
end123
end456
守护线程 等待非守护子线程以及主线程结束之后,结束.
# 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}')