并发编程前言:
1、网络应用
1)爬虫 直接应用并发编程;
2)网络框架 django flask tornado 源码-并发编程
3)socketserver 源码-并发编程
2、运维领域
1)自动化开发-运维开发(机器的批量管理,任务的批量执行等)
一、操作系统/应用程序
a、硬件
- 硬盘
- CPU
- 主板
- 显卡
- 内存
- 电源
. . . . . .
b、装系统(软件)
- 系统就是一个由程序员写出来的软件,该软件用于控制计算机的硬件,让他们之间进行相互配合。
c、安软件(安装应用程序)
- 百度云
- pycharm
. . . . . .
二、并行与并发
并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)
并行:并行:同时运行,只有具备多个cpu才能实现并行
三、线程和进程
a、单进程、单线程的应用程序,比如:
print('666')
b、到底什么是线程?什么是进程?
python自己没有这玩意,python中调用的操作系统的线程和进程。
c、单进程、多线程的应用程序,比如:
import threading print('666') def func(arg): print(arg) t = threading.Thread(target=func,args=(11,)) # 创建一个线程 t.start()
一个应用程序(软件),可以有多个进程(默认只有一个),一个进程中可以创建多个线程(默认一个)。
问题1:为什么有这把GIL锁?
python语言的创始人在开发这门语言时,目的是快速把语言开发出来,如果加上GIL锁(c语言加锁),切换时按照100条字节指令来进行线程间的切换。
问题2:进程和线程的区别?
线程,线程是cpu工作的最小单元;
进程,进程是cpu资源分配的最小单元,为线程提供一个资源共享的空间;
一个进程中可以有多个线程,一个进程中默认有一个主线程;
对于python来说,它的进程和线程和其他语言有差异,有GIL锁。它保证一个进程中同一时刻只有一个线程被cpu调度;
IO密集型操作可以使用多线程,计算密集型可以使用多进程;
问题3:线程创建的越多越好吗?
不是,线程之间进行切换,要做上下文管理。
线程和进程的效率对比:线程的效率非常高,并且线程开启不需要消耗什么资源
线程的创建
第一中创建方式:
threading四ruai顶 Thread死ruai的
import time from threading import Thread from multiprocessing import Process def func(n): print(n) if __name__ == '__main__': # t = Thread(target=func,args=('我是线程',)) # t.start() #速度非常快 p = Process(target=func,args=('我是进程',)) p.start() print('主线程结束')
第二种创建方式: 函数继承Thread
class MyThread(Thread): def run(self): print('sb明杰') if __name__ == '__main__': t = MyThread() t.start() print('主线程结束')
同一进程下,线程是资源共享的
import time from threading import Thread from multiprocessing import Process num = 100 def func(): global num num = 0 if __name__ == '__main__': t = Thread(target=func,) t.start() t.join() print(num)
线程资源共享数据不安全,通过锁来解决数据不安全的问题,线程模块里面引入的锁
锁(同步锁互斥锁):保证数据安全,但是牺牲了效率,同步执行锁内的代码
import time from threading import Thread,Lock Lock(拉客) num = 100 def func(t_lock): global num # num -= 1 t_lock.acquire() mid = num mid = mid - 1 time.sleep(0.0001) num = mid t_lock.release() if __name__ == '__main__': t_lock = Lock() #锁对象(同步锁,互斥锁) t_list = [] for i in range(10): t = Thread(target=func,args=(t_lock,)) t.start() t_list.append(t) [tt.join() for tt in t_list] print('主线程>>>',num)
解决死锁线程,用递归锁
互相抢到了对方的需要的锁,导致双方相互等待,程序没法进行
import time from threading import Thread,Lock,RLock #递归锁 class MyThread(Thread): def __init__(self,lockA,lockB): super().__init__() self.lockA = lockA self.lockB = lockB def run(self): self.f1() self.f2() def f1(self): self.lockA.acquire() print('我拿了A锁') self.lockB.acquire() print('我是一个很好的客户!') self.lockB.release() self.lockA.release() def f2(self): self.lockB.acquire() time.sleep(0.1) print('我拿到了B锁') self.lockA.acquire() print('我是一名合格的技师') self.lockA.release() self.lockB.release() if __name__ == '__main__': # lockA = Lock() # lockB = Lock() # lockA = lockB = Lock() #不要这么写,别自己玩自己,锁自己 lockA = lockB = RLock() t1 = MyThread(lockA,lockB) t1.start() t2 = MyThread(lockA,lockB) t2.start() print('我是经理')
线程进程效率对比
import time from threading import Thread from multiprocessing import Process def func(n): num = 0 for n1 in range(n): num += n1 print('num',num) if __name__ == '__main__': t_s_t = time.time() t_list = [] for i in range(10): t = Thread(target=func,args=(10,)) t.start() #速度非常快 t_list.append(t) [tt.join() for tt in t_list] t_e_t = time.time() t_dif_t = t_e_t - t_s_t #获取了线程的执行时间 p_s_t = time.time() #开始时间 p_list = [] for ii in range(10): p = Process(target=func,args=(10,)) p.start() p_list.append(p) [pp.join() for pp in p_list] p_e_t = time.time() #结束时间 p_dif_t = p_e_t - p_s_t #时间差 print('线程>>>>',t_dif_t) print('进程....',p_dif_t) print('主线程结束')
信号量
信号量:控制同时能够进入锁内去执行代码的线程数量(进程数量),维护了一个计数器,刚开始创建信号量的时候假如设置的是4个房间,进入一次acquire就加一,出来一次就减一,如果计数器为0的时候,才可以继续抢钥匙,这样其他任务等待,这样的话,其他任务都是同步的状态,而进入acquire里面去执行的那四个任务是异步执行的
import time from threading import Thread, Semaphore def func1(s): s.acquire() time.sleep(1) print('大宝剑!!!') s.release() if __name__ == '__main__': s = Semaphore(4) for i in range(10): t = Thread(target=func1,args=(s,)) t.start()
主线程等待子线程的原因
import time from threading import Thread from multiprocessing import Process def func(n): time.sleep(5) print(n) if __name__ == '__main__': # 主线程等待的是子线程的任务全部执行完毕 t = Thread(target=func, args=('我是子线程',)) t.start() # 速度非常快 # 主进程等待的是给子进程收尸 # p = Process(target=func,args=('我是子进程',)) # p.start() # print('主进程结束!!') print('主线程结束')
守护线程
主线程等待所有非守护进程的结束才结束,主线程的代码运行结束,还要等待守护线的执行完毕,这个过程中守护线程还存在
守护进程
主进程代码结束程序并没有结束,并且主进程还存在,进程等待其他的子进程执行结束以后,为子进程收尸,注意一个问题:主进程的代码运行结束守护进程跟着结束,
代码如下
import time from threading import Thread from multiprocessing import Process def func1(n): time.sleep(5) print(n) def func2(n): time.sleep(3) print(n) if __name__ == '__main__': # 进程 p1 = Process(target=func1,args=('我是子进程1号',)) p1.daemon = True #设置守护,在start之前加 p1.start() p2 = Process(target=func2, args=('我是子进程2号',)) p2.start() t1 = Thread(target=func1, args=('我是子xiancheng1号',)) t1.daemon = True t1.start() t2 = Thread(target=func2, args=('我是子xiancheng2号',)) t2.start() print('主进程结束!!') print('主线程结束')
线程的其他方法 1
from threading import Thread import threading import time from multiprocessing import Process import os def work(): import time time.sleep(1) # print('子线程',threading.get_ident()) #2608 if __name__ == '__main__': #在主进程下开启线程 t=Thread(target=work) #死如唉的 t.start() current_thread(扣的死如爱的) print(threading.current_thread())#主线程对象 #<_MainThread(MainThread, started 1376)> print(threading.current_thread().getName()) #主线程名称 #MainThread print(threading.current_thread().ident) #主线程ID #1376 print(threading.get_ident()) #主线程ID #1376 time.sleep(3) print(threading.enumerate()) # 连同主线程在内有两个运行的线程, enumerate枚举(额牛木蕊特) print(threading.active_count()) # 2 active_count(啊可特康特) print('主线程/主进程')
事件:
from threading import Thread,Event Event(一温特) e = Event() #e的状态有两种,False True,当事件对象的状态为False的时候,wait的地方会阻塞 e.set() #将事件对象的状态改为True e.clear() #将事件对象的状态改为Flase clear(克雷尔) print('在这里等待') e.wait() #阻塞 wait(威特) print('还没好!!')
线程队列
队列有三种模式
先进先出:
import queue q=queue.Queue() q.put('first') # q.put_nowait() #不等待 print(q.get()) q.get_nowait() #没有数据就报错,可以通过try来搞 脑为特
先进后出:
import queue q=queue.LifoQueue() #队列,类似于栈,栈我们提过吗,是不是先进后出的顺序啊 q.put('third') print(q.get())
优先级队列:
import queue q=queue.PriorityQueue() #put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高 q.put((-10,'a')) q.put((-5,'a')) #负数也可以 q.put((20,'ws')) #如果两个值的优先级一样,那么按照后面的值的acsii码顺序来排序,如果字符串第一个数元素相同,比较第二个元素的acsii码顺序 q.put((20,'wd')) q.put((20,{'a':11})) #TypeError: unorderable types: dict() < dict() 不能是字典 q.put((20,('w',1))) #优先级相同的两个数据,他们后面的值必须是相同的数据类型才能比较,可以是元祖,也是通过元素的ascii码顺序来排序 ''' 结果(数字越小优先级越高,优先级高的优先出队): '''
线程池:
import time from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from threading import current_thread def func(n): time.sleep(1) # print(n,current_thread().ident) return n**2 if __name__ == '__main__': t_p = ThreadPoolExecutor(max_workers = 4) max_workers(马克思我K儿死) map_res = t_p.map(func,range(10)) #异步执行的,map自带join功能 print(map_res) print([i for i in map_res])
回调函数:
import time from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from threading import current_thread def func(n): time.sleep(1) print(n,current_thread().getName()) return n**2 def func2(n): print('>>>>>>>',n.result()) if __name__ == '__main__': t_p = ThreadPoolExecutor(max_workers = 4) for i in range(3): t_p.submit(func,i).add_done_callback(func2) add_done_callback(俺的 当 考班可) print('主线程结束')
线程池的一些其他方法:
ThreadPoolExecutor(死日无爱的 噗奥 A克赛K特)
ProcessPoolExecutor(噗赛死 噗奥 A克赛K特)
import time from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from threading import current_thread def func(n): time.sleep(1) # print(n,current_thread().ident) return n**2 if __name__ == '__main__': t_p = ThreadPoolExecutor(max_workers = 4) t_res_list = [] for i in range(10): res_obj = t_p.submit(func,i)#异步提交了10个任务,submit(色卖特) t_res_list.append(res_obj) t_p.shutdown() #close + join shutdown(莎当) close(可篓子) for e_res in t_res_list: print(e_res.result())#他和get一样 result(蕊造特)
多线程和多进程进行纯计算的效率
import time from multiprocessing import Process from threading import Thread def func(): num = 0 for i in range(1,10000000): num += i # def func(): # time.sleep(2) # print('xxxxxxxx') if __name__ == '__main__': p_s_t = time.time() p_list = [] for i in range(10): p = Process(target=func,) p_list.append(p) p.start() [pp.join() for pp in p_list] p_e_t = time.time() p_dif_t = p_e_t - p_s_t t_s_t = time.time() t_list = [] for i in range(10): t = Thread(target=func,) t_list.append(t) t.start() [tt.join() for tt in t_list] t_e_t = time.time() t_dif_t = t_e_t - t_s_t print('多进程执行的时间',p_dif_t) print('多线程执行的时间',t_dif_t) ''' 多进程执行的时间 4.5982630252838135 多线程执行的时间 8.339477062225342 '''
GIL锁:
并发执行的效率(在没有IO的情况下,两个纯计算的任务 )
import time def func1(): num2 = 0 for i in range(1000001): num2 += i yield # print('执行到下一个yield',current_thread().name) def func2(): g = func1() next(g) sum = 0 for i in range(1000000): # g.send(i) sum += i next(g) s_t = time.time() func2() print('协程的时间',time.time() - s_t)
串行执行的效率
def func1(): num2 = 0 for i in range(1000001): num2 += i # print('执行到下一个yield',current_thread().name) def func2(): sum = 0 for i in range(1000000): sum = sum + i s_t = time.time() func1() func2() print('串行的时间',time.time() - s_t) ''' 协程的时间 0.319796085357666 串行的时间 0.14291739463806152 '''