进程跟线程的执行效率对比
同样任务线程的执行效率
import time
from threading import Thread
from multiprocessing import Process
# def func(a):
# a+=1
#
# if __name__ == '__main__':
# start=time.time()
# t1=[]
# for i in range(50):
# t=Thread(target=func,args=(i,)) #分出50个线程,来执行任务
# t.start() #任务开始
# t1.append(t) #
# for t in t1:
# t.join()
# print("主线程")
# print(time.time()-start)
# statr=time.time()
同样任务进程的执行效率
import time from threading import Thread from multiprocessing import Process def func(a): a+=1 if __name__ == '__main__': start=time.time() t1=[] for i in range(50): p=Process(target=func,args=(i,)) p.start() t1.append(p) for t in t1: t.join() print("主进程") print(time.time() - start)
# start 开始 join 等待
# terminate 强制停止一个进程 在线程中没有
线程之间的数据共享
from threading import Thread n=100 def func(): global n n=n-1 if __name__ == '__main__': t1=[] for i in range(100): t=Thread(target=func) t.start() t1.append(t) for w in t1: t.join() print(n)
因为线程之间的数据是共享的,难免会造成数据混乱,所以用守护线程
import time from threading import Thread def a1(): while 1: print(True) time.sleep(0.5) def a2(): print("in t2 start") time.sleep(3) print("in t2 end") if __name__ == '__main__': t1=Thread(target=a1) t1.setDaemon(True) t1.start() t2 = Thread(target=a2) t2.start() time.sleep(1) print("主线程")
主线程如果结束了 那么整个进程就结束
守护线程 会等待主线程结束之后才结束.
主进程 等待 守护进程 子进程
守护进程 只守护主进程的代码就可以了
守护线程不行 主线程如果结束了 那么整个进程就结束 所有的线程就都结束
from threading import Thread,get_ident
开启线程的第二种方式和查看线程id
from threading import Thread,get_ident class MyThread(Thread): def __init__(self,args): super().__init__() self.args=args def run(self): print("in my thread:", get_ident(),self.args) print("main",get_ident()) t=MyThread("wahaha") #主线程id t.start() #子线程 id
线程中的方法
Thread 开启一个线程
get_ident 获得线程的运行id
currentThread 给每个子线程一个名字 跟id
enumerate, 正在运行的线程
activeCount 正在运行的线程的数量 相当于len(enumerate())
import time from threading import Thread,get_ident,currentThread,enumerate,activeCount # 开启线程的第二种方式和查看线程id class MyThread(Thread): def __init__(self,args): super().__init__() # Thread类的init,在这个方法中做了很多对self的赋值操作,都是给创建线程或者使用线程的时候用的 self.args = args def run(self): time.sleep(0.1) print(1) print(currentThread()) print('in my thread : ',get_ident(),self.args) print('main',get_ident()) t = MyThread('wahaha') # print(t.is_alive()) t.start() print(activeCount()) # 正在运行的线程的数量 len(enumerate()) # print(enumerate()) # print('t : ',t) # print(t.is_alive())
# thread对象的其他方法 : isAlive ,setname,getname
# threading模块的方法 : currentTread,activeCount,enumerate
=======================精讲join==========
import time from threading import Thread from multiprocessing import Process def func(): for i in range(5): print('in thread') time.sleep(0.2) if __name__ == '__main__': p_l = [] for i in range(10): p = Process(target=func) p.start() p_l.append(p) p_l[0].join() # 保证第0个进程结束了 p_l[1].join() # p1执行完了么? 执行完了就不阻塞 p_l[2].join() p_l[3].join() p_l[4].join() p_l[5].join() p_l[6].join() p_l[7].join() p_l[8].join() p_l[9].join() # p9执行完了么 ? # p.join() # 主进程被阻塞,等待p结束之后再继续往下执行 for i in range(5): print('*'*10) time.sleep(0.2)
==================锁===========
在多个进程/线程同时访问一个数据的时候就会产生数据的不安全现象
多进程 访问文件
多线程 同时去访问一个数据
GIL 全局解释器锁
在同一个进程里的每一个线程同一时间只能有一个线程访问cpu
尽量不要设置全局变量
只要在多线程/进程之间用到全局变量 就加上锁
from threading import Lock,Thread lock = Lock() lock.acquire() noodle = 100 def func(name,lock): global noodle lock.acquire() noodle -= 1 lock.release() print('%s吃到面了'%name) if __name__ == '__main__': lock = Lock() # 线程锁 互斥锁 t_lst = [] for i in range(10): t = Thread(target=func,args=(i,lock)) t.start() t_lst.append(t) for t in t_lst: t.join() print(noodle)
经典的科学家吃面问题 死锁
import time from threading import Thread,Lock lock = Lock() noodle_lock = Lock() fork_lock = Lock() def eat1(name): noodle_lock.acquire() print('%s拿到了面' % name) fork_lock.acquire() print('%s拿到了叉子' % name) print('%s在吃面'%name) time.sleep(0.5) fork_lock.release() # 0.01 noodle_lock.release() # 0.01 def eat2(name): fork_lock.acquire() # 0.01 print('%s拿到了叉子' % name) # 0.01 noodle_lock.acquire() print('%s拿到了面' % name) print('%s在吃面'%name) time.sleep(0.5) noodle_lock.release() fork_lock.release() eat_lst = ['alex','wusir','太白','yuan'] for name in eat_lst: # 8个子线程 7个线程 3个线程eat1,4个线程eat2 Thread(target=eat1,args=(name,)).start() Thread(target=eat2,args=(name,)).start() """alex拿到了面 alex拿到了叉子 alex在吃面 alex拿到了叉子 wusir拿到了面 """
解决方案第一版
import time from threading import Thread,Lock lock = Lock() def eat1(name): lock.acquire() print('%s拿到了面' % name) print('%s拿到了叉子' % name) print('%s在吃面'%name) time.sleep(0.5) lock.release() # 0.01 def eat2(name): lock.acquire() # 0.01 print('%s拿到了叉子' % name) # 0.01 print('%s拿到了面' % name) print('%s在吃面'%name) time.sleep(0.5) lock.release() eat_lst = ['alex','wusir','太白','yuan'] for name in eat_lst: # 8个子线程 7个线程 3个线程eat1,4个线程eat2 Thread(target=eat1,args=(name,)).start() Thread(target=eat2,args=(name,)).start()
解决方案第二版
import time from threading import Thread,RLock lock = RLock() def eat1(name): lock.acquire() print('%s拿到了面' % name) lock.acquire() print('%s拿到了叉子' % name) print('%s在吃面'%name) time.sleep(0.5) lock.release() # 0.01 lock.release() # 0.01 def eat2(name): lock.acquire() # 0.01 print('%s拿到了叉子' % name) # 0.01 lock.acquire() print('%s拿到了面' % name) print('%s在吃面'%name) time.sleep(0.5) lock.release() lock.release() eat_lst = ['alex','wusir','太白','yuan'] for name in eat_lst: # 8个子线程 7个线程 3个线程eat1,4个线程eat2 Thread(target=eat1,args=(name,)).start() Thread(target=eat2,args=(name,)).start()
死锁: 多把锁同时应用在多个线程中
互斥锁和递归锁哪个好
递归锁 快速恢复服务
死锁问题的出现 是程序的设计或者逻辑的问题
还应该进一步的排除和重构逻辑来保证使用互斥锁也不会发生死锁
互斥锁和递归锁的区别
互斥锁 就是在一个线程中不能连续多次ACQUIRE
递归锁 可以在同一个线程中acquire任意次,注意acquire多少次就需要release多少次
====================信号量=锁+计数器===============================
import time from multiprocessing import Semaphore,Process,Pool def ktv1(sem,i): pass def ktv2(i): i+=1 if __name__ == '__main__': sem=Semaphore(5) start=time.time() p1=[] for i in range(100): p=Process(target=ktv1,args=(sem,i)) p.start() p1.append(p) for p in p1: p.join() print("###",time.time()-start) start = time.time() p = Pool(5) p_l = [] for i in range(100): ret = p.apply_async(func=ktv2, args=(sem, i)) p_l.append(ret) p.close() p.join() print('***',time.time() - start)
池 效率高
池子里有几个一共就起几个
不管多少任务 池子的个数是固定的
开启进程和关闭进程这些事都是需要固定的开销
就不产生额外的时间开销
且进程程池中的进程数控制的好,那么操作系统的压力也小
信号量
有多少个任务就起多少进程/线程
可以帮助你减少操作系统切换的负担
但是并不能帮助你减少进/线程开启和关闭的时间
==============事件===============================
# wait
# 等 到 事件内部的信号变成True就不阻塞了
# set
# 设置信号变成True
# clear
# 设置信号变成False
# is_set
# 查看信号是否为True
实例代码 数据库连接
import time # import random # from threading import Event,Thread # def check(e): # '''检测一下数据库的网络和我的网络是否通''' # print('正在检测两台机器之间的网络情况 ...') # time.sleep(random.randint(0,2)) # e.set() # # def connet_db(e): # n = 0 # while n < 3: # if e.is_set(): # break # else: # e.wait(0.5) # n += 1 # if n == 3: # raise TimeoutError # print('连接数据库 ... ') # print('连接数据库成功~~~') # # e = Event() # Thread(target=connet_db,args=(e,)).start() # Thread(target=check,args=(e,)).start()
===================条件======================
from threading import Condition # acquire # release # wait 阻塞 # notify 让wait解除阻塞的工具 # wait还是notify在执行这两个方法的前后 必须执行acquire和release # from threading import Condition,Thread # def func(con,i): # con.acquire() # # 判断某条件 # con.wait() # print('threading : ',i) # con.release() # # con = Condition() # for i in range(20): # Thread(target=func,args=(con,i)).start() # con.acquire() # # 帮助wait的子线程处理某个数据直到满足条件 # con.notify_all() # con.release() # while True: # num = int(input('num >>>')) # con.acquire() # con.notify(num) # con.release()
================定时器============
from threading import Timer def func(): print('执行我啦') # interval 时间间隔 Timer(0.2,func).start() # 定时器 # 创建线程的时候,就规定它多久之后去执行