标签:lex 资源分配 运算 线程阻塞 解释器 [] 代码段 rgs 语言
线程与进程的区别:
注意: 在pychon中 算法类的运算变成 使用进程会更好.
因为pychon中有个GIL:全局解释锁(只有C语言编写的pychon解释器才有.(Cpychon))
对于线程来说, 因为有了GIL, 所以没有真正的并发.
线程有分为用户级线程和内核级线程.(了解)
用户级线程: 对于程序猿 来说的, 这样的线程完全被程序员控制执行, 调度.
内核级线程: 对于计算机内核来说的, 这样的线程完全被内核控制调度, 不受程序猿调度.
线程和进程的比较:
thread - 线程
import thread 操作线程的模块
import threading 用这个去操作线程
(1) cpu切换进程要比cpu切换线程 慢很多
在python中,如果IO操作过多的话,使用多线程最好了
(2) 在同一个进程内,所有线程共享这个进程的pid,也就是说所有线程共享所属进程的所有资
源和内存地址
(3) 在同一个进程内,所有线程共享该进程中的全局变量
(4) 因为有GIL锁的存在,在Cpython中,没有真正的线程并行。但是有真正的多进程并行
当你的任务是计算密集的情况下,使用多进程好
总结:在CPython中,IO密集用多线程,计算密集用多进程
(5)关于守护线程和守护进程的事情(注意:代码执行结束并不代表程序结束)
守护进程:要么自己正常结束,要么根据父进程的代码执行结束而结束
守护线程:要么自己正常结束,要么根据父线程的执行结束而结束
初识线程:
进程由 代码段 数据段 PCB组成(process control block 进程控制块)
线程由 代码段 数据段 TCB组成(thread control block 线程控制块)
# 函数开启线程方法:
1 # import threading # 导入模块的方法一 2 from threading import Thread # 导入线程函数的方法二 3 4 5 def func(i): # 定义一个子线程 6 print(i) 7 8 9 10 if __name__ == ‘__main__‘: 11 for i in range(200): 12 q = Thread(target=func,args=(i,)) # 13 q.start()
1 # 类方法开启线程的方法: 2 # class MyThread(Thread): # 实例化一个类. 将线程模块设置为形参. 3 # def __init__(self): # 初始化线程 4 # super(MyThread, self).__init__() 5 # def run(self): 6 # print(‘我是一个子线程‘) 7 # 8 # t = MyThread() 9 # t.start()
线程与进程的对比01:
from multiprocessing import Process from threading import Thread import time def func(): pass if __name__ == ‘__main__‘: start = time.time() for i in range(1000): p = Process(target=func) p.start() print(‘开100个进程的时间:‘,time.time() - start) start = time.time() for i in range(1000): p = Thread(target=func) p.start() print(‘开100个线程的时间:‘, time.time() - start)
# 得到的结果线程所用时间远远小于进程时间. 从而判断线程切换CPU的速度远远大于进程.
# 在python 中, 如果IO操作过多的时候, 使用多线程.
线程与进程的对比02
1 from multiprocessing import Process 2 from threading import Thread 3 import time,os 4 5 6 7 def func(name): 8 print(‘我是一个%s,我的pid是%s‘%(name,os.getpid())) 9 10 11 if __name__ == ‘__main__‘: 12 13 print(‘我是main,我的pid是%s‘%(os.getpid())) 14 for i in range(10): 15 p = Process(target=func,args=(‘进程‘,)) 16 p.start() 17 18 for i in range(10): 19 p = Thread(target=func,args=(‘线程‘,)) 20 p.start()
# 在一个进程中, 所有的线程都共享这个进程的pid号,
# 也就是说所有的线程都共享这个进程的所有资源和内存地址.
线程与进程的对比03:
多进程时候也同样共享所属进程中的全局变量(所有资源和内存地址)
from multiprocessing import Process from threading import Thread,Lock import time,os def func(): 定义一个func线程. global num 获得全局变量的num. tmp = num time.sleep(0.1)
# 此时每条线程都会睡眠0.1秒(全局解释锁允许线程的反应最大速度为5毫秒),
# 后被T出CPU, 线程会继续执行,到最后得到的结果为相同的都为99 num = tmp - if __name__ == ‘__main__‘: num = 100 t_l = [] for i in range(100): t = Thread(target=func) t.start() t_l.append(t) # time.sleep(1) [t.join() for t in t_l] print(num)
线程三种被迫放弃CPU的过程:
2线程的使用方法
(1)锁机制
递归锁
RLock() 可以有无止尽的锁,但是会有一把万能钥匙
互斥锁:
Lock() 一把钥匙配一把锁
GIL:全局解释器锁
锁的是线程,是CPython解释器上的一个锁,锁的是线程,意思是在同一时间只允许一个线程访问cpu
(2) 信号量:
from threading import Semaphore
去看多进程的信号量(3) 事件
from threading import Event
去看多进程的事件机制(4) 条件
from threading import Condition
条件是让程序员自行去调度线程的一个机制
# Condition涉及4个方法
# acquire()
# release()
# wait() 是指让线程阻塞住
# notify(int) 是指给wait发一个信号,让wait变成不阻塞
# int是指,你要给多少给wait发信号(5) 定时器
from threading import Timer
# Timer(time,func)
# time:睡眠的时间,以秒为单位
# func:睡眠时间之后,需要执行的任务
互斥锁:
1 from multiprocessing import Process 2 from threading import Thread,Lock 3 import time,os 4 5 # l = Lock()# 一把钥匙配一把锁 6 # l.acquire() 7 # print(‘abc‘) 8 # l.acquire()# 程序会阻塞住 陷入死锁了 9 # print(123)
死锁示例:
1 from multiprocessing import Process 2 from threading import Thread,Lock 3 import time,os 4 5 6 7 def man(l_tot,l_pap): 8 l_tot.acquire()# 是男的获得厕所资源,把厕所锁上了 9 print(‘alex在厕所上厕所‘) 10 time.sleep(1) 11 l_pap.acquire()# 男的拿纸资源 12 print(‘alex拿到卫生纸了!‘) 13 time.sleep(0.5) 14 print(‘alex完事了!‘) 15 l_pap.release()# 男的先还纸 16 l_tot.release()# 男的还厕所 17 18 def woman(l_tot,l_pap): 19 l_pap.acquire() # 女的拿纸资源 20 print(‘小雪拿到卫生纸了!‘) 21 time.sleep(1) 22 l_tot.acquire() # 是女的获得厕所资源,把厕所锁上了 23 print(‘小雪在厕所上厕所‘) 24 time.sleep(0.5) 25 print(‘小雪完事了!‘) 26 l_tot.release() # 女的还厕所 27 l_pap.release() # 女的先还纸 28 29 30 if __name__ == ‘__main__‘: 31 l_tot = Lock() 32 l_pap = Lock() 33 t_man = Thread(target=man,args=(l_tot,l_pap)) 34 t_woman = Thread(target=woman,args=(l_tot,l_pap)) 35 t_man.start() 36 t_woman.start()
死锁解决方法:(配一把公共钥匙)
1 from multiprocessing import Process 2 from threading import Thread,RLock 3 import time,os 4 # RLock是递归锁 --- 是无止尽的锁,但是所有锁都有一个共同的钥匙 5 # 想解决死锁,配一把公共的钥匙就可以了。 6 7 def man(l_tot,l_pap): 8 l_tot.acquire()# 是男的获得厕所资源,把厕所锁上了 9 print(‘alex在厕所上厕所‘) 10 time.sleep(1) 11 l_pap.acquire()# 男的拿纸资源 12 print(‘alex拿到卫生纸了!‘) 13 time.sleep(0.5) 14 print(‘alex完事了!‘) 15 l_pap.release()# 男的先还纸 16 l_tot.release()# 男的还厕所 17 18 def woman(l_tot,l_pap): 19 l_pap.acquire() # 女的拿纸资源 20 print(‘小雪拿到卫生纸了!‘) 21 time.sleep(1) 22 l_tot.acquire() # 是女的获得厕所资源,把厕所锁上了 23 print(‘小雪在厕所上厕所‘) 24 time.sleep(0.5) 25 print(‘小雪完事了!‘) 26 l_tot.release() # 女的还厕所 27 l_pap.release() # 女的先还纸 28 29 30 if __name__ == ‘__main__‘: 31 l_tot = l_pap = RLock() # 将Lock 换成RLock就可以解开死锁. 32 t_man = Thread(target=man,args=(l_tot,l_pap)) 33 t_woman = Thread(target=woman,args=(l_tot,l_pap)) 34 t_man.start() 35 t_woman.start()
# 而‘万能钥匙‘只有一把, 所以只能一次运行结束一个线程, 才能去解决另一个线程, 是另一个线程也结束.
递归锁:
递归锁
RLock() 可以有无止尽的锁,但是会有一把万能钥匙
1 from threading import RLock 2 3 s = RLock() 4 s1 = RLock() 5 s.acquire() 6 s.acquire() 7 s.acquire() 8 s.acquire() 9 s.acquire() 10 s.acquire() 11 print(123)
# 可以有无止境的锁.但是只有一把万能钥匙, 所以一次只能结束一条线程.
# 注意:
万能钥匙(递归锁 RLock() ) 和互斥锁( Lock() ) 要根据实际情况来使用!!!
而在变成中一定要细心, 可以多用print()去一步一步实现.
锁机制
递归锁
RLock() 可以有无止尽的锁,但是会有一把万能钥匙
互斥锁:
Lock() 一把钥匙配一把锁
GIL:全局解释器锁
锁的是线程,是CPython解释器上的一个锁,锁的是线程,意思是在同一时间只允许一个线程访
信号量相关:
from threading import Semaphore
与多进程的信号量类似
from threading import Semaphore,Thread import time def func(sem,i): sem.acquire() # 拿钥匙锁门 print(‘第%s个人进入屋子‘%i) time.sleep(2) print(‘第%s个人离开屋子‘%i) sem.release() # 还钥匙开门
# if __name__ == ‘__main__‘: # 在线程代码中, 可有可无, pycham解释器会自动补齐(其他解释器还没实践.)
sem = Semaphore(5) # 相当于5把钥匙1把锁, 一次可以进去5个人. for i in range(20): # 定义20个人 t = Thread(target=func,args=(sem,i)) t.start()
事件: ( Event() )
from threading import Event
与多进程的事件机制类似
1 from threading import Thread,Event 2 import time,random 3 4 def conn_mysql(e,i): 5 count = 1 6 while count <= 3: 7 if e.is_set(): 8 print(‘第%s个人连接成功!‘%i) 9 break 10 print(‘正在尝试第%s次重新连接...‘%(count)) 11 e.wait(0.5) 12 count += 1 13 14 def check_mysql(e): 15 print(‘\033[42m 数据库正在维护 \033[0m‘) 16 time.sleep(random.randint(1,2))
# 连接服务器是否成功受此行代码影响, 如果睡1秒的话, conn_mysql 函数中尝试两次(即循环两次就够1秒,) 从而能够登陆成功.
# 如果睡眠时间是2秒, conn_mysql三次循环以后,函数会结束, 传输的登陆请求会接收不到,从而登陆不成功. 17 e.set() 18 19 20 if __name__ == ‘__main__‘: 21 e = Event() 22 t_check = Thread(target=check_mysql,args=(e,)) 23 t_check.start() 24 25 for i in range(10): 26 t_conn = Thread(target=conn_mysql,args=(e,i)) 27 t_conn.start()
#
条件(Condition())
from threading import Condition
条件是让程序员自行去调度线程的一个机制
# Condition涉及4个方法
# acquire()
# release()
# wait() 是指让线程阻塞住
# notify(int) 是指给wait发一个信号,让wait变成不阻塞
# int是指,你要给多少给wait发信号
定时器:
from threading import Timer
# Timer(time,func)
# time:睡眠的时间,以秒为单位
# func:睡眠时间之后,需要执行的任务
from threading import Timer# 定时器 def func(): print(‘就是这么nb!‘) Timer(2.5,func).start() # Timer(time,func) # time:睡眠的时间,以秒为单位 # func:睡眠时间之后,需要执行的任务
标签:lex 资源分配 运算 线程阻塞 解释器 [] 代码段 rgs 语言
原文地址:https://www.cnblogs.com/hfbk/p/9539010.html