守护进程
from threading import Thread
import time
import os
def task(name):
print('%s is running ' % name)
time.sleep(1)
print('%s is over ' % name)
def test():
time.sleep(3)
print('over')
if __name__ == '__main__':
t = Thread(target=task,args=('lichang',))
test = Thread(target=test)
t.daemon = True # 开启守护线程
t.start()
test.start()
print('主')
线程互斥锁
from threading import Thread, Lock
import time
money = 100
mutex = Lock()
def task():
global money
mutex.acquire()
tmp = money
time.sleep(0.1)
money = tmp - 1
mutex.release()
if __name__ == '__main__':
# mutex = Lock()
t_list = []
for i in range(100):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(money)
'''数据错乱,加锁处理'''
GIL全局解释锁
Python解释器有多个版本
普遍使用的是Cpython
- GIL不是Python的特点而是Cpython的特点
- GIL是保证解释器级别的数据安全
- GIL会导致同一个进程下的多个线程无法同时运行
- 针对不同的数据还是需要不同的锁处理
- 解释型语言的通病:同一个进程下多个线程无法利用多核优势
在cpython解释器中GIL是一把互斥锁,用来阻止同一个进程下的多个线程的同时执行
同一个进程下的多个线程无法利用多核优势
Python的多线程是不是没有什么用?
因为Cpython中的内存管理不是线程安全的
内存管理(垃圾回收机制)
- 应用计数
- 标记清除
- 分代回收
同一进程下的多线程无法利用多核优势,是不是就没什么用
多线程是否有用要看具体情况
多进程:相对浪费资源
多线程:更加节省资源
IO密集型计算密集型
IO密集型条件下使用多线程效率更高
计算密集型条件下使用多进程效率更高
多进程和多线程都有各自的优势
并且在实战写项目时通常可以:多线程下面再开设多线程
总结
- 开启进程的两种方式
开进程和开线程的步骤基本是一样的,只是导入的模块不一样而已
开进程代码必须写在main下面,而开进程则无需这么做
类的对象调用方法
类的继承重写Run方法
- TCP服务端实现并发
将接客与服务的活分开
- 线程对象的join方法
等待当前线程对象结束之后,再继续往下执行
- 同一个进程内的多个线程数据是共享的
同一个进程内可以开设多个线程
进程:资源单位
线程:执行单位
- 线程对象属性和方法
current_thread
active_count 当前活跃的线程
- 守护线程
主线程必须等待所有非守护线程的结束才能结束
t.daemon = True
t.start()
- 线程互斥锁
当多个线程在操作同一份数据的时候可能会造成数据的错乱
这时为了保证数据的安全,我们通常会加锁处理
锁:
将并发变成串行,降低了程序的运行效率但是保证了数据的安全
一般不会遇到锁的问题,底层封装已处理
- GIL全局解释器锁
1. GIL不是Python的特点而是Cpython的特点
2. GIL本身也是一把互斥锁,但是它是解释器级别的
3. 它的存在是因为Cpython解释器内存管理不是线程安全
垃圾回收机制
- 应用计数
- 标记清除
- 分代回收
4. 也就意味着GIL的存在导致了同一个进程下的多个线程无法利用多核优势(不能同时运行)
5. 针对不同的数据应该加不同的锁来保证安全
- python多线程是否有用
结合任务的具体类型再做判断
应该对任务分两种情况讨论
IO密集型
多线程更加节省资源
计算密集型
多进程更加合理
多进程和多线程均有用,且后面的操作都是多进程加多线程从而达到效率最大化