1.进程
-
进程
-
进程是资源分配的最小单位( 内存、cpu、网络、io)
-
一个运行起来的程序就是一个进程
- 什么是程序(程序是我们存储在硬盘里的代码)
- 硬盘(256G)、内存条(8G)
- 当我们双击图标,打开程序的时候,实际上就是通过I/O操作(读写)内存条里面
- 内存条就是我们所指的资源
- CPU分时
- CPU比你的手速快多了,分时处理每个线程,但是由于太快然你觉得每个线程都是独占cpu
- cpu是计算,只有时间片到了,获取cpu,线程真正执行
- 当你想使用 网络、磁盘等资源的时候,需要cpu的调度
-
进程具有独立的内存空间,所以没有办法相互通信
- 进程如何通信
- 进程queue
- pipe
- managers
- RabbitMQ、redis等
- 进程如何通信
-
为什么需要进程池
- 一次性开启指定数量的进程
- 如果有十个进程,有一百个任务,一次可以处理多少个(一次性只能处理十个)
- 防止进程开启数量过多导致服务器压力过大
-
from multiprocessing import Pool
import os, time
def worker(i):
print('第%d次打印,我爱你中国'%(i))
time.sleep(1)
if __name__ == '__main__':
po = Pool(20) # 定义一个进程池,最大进程数20
for i in range(1,101):
# Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
# 每次循环将会用空闲出来的子进程去调用目标
po.apply_async(worker, args = (i,))
print("----start----",end='\n')
po.close() # 关闭进程池,关闭后po不再接收新的请求
po.join() # 等待po中所有子进程执行完成,必须放在close语句之后
print("-----end-----")
创建进程
1、导包 import multiprocessing
2、创建任务 函数
3、用multiprocessing.Process(target=函数名)
4、开启进程 start()
5、join()
6、terminate() 立即结束子进程
import os
from multiprocessing import Process
import time
num = 100
def func1():
global num
num +=50
print(num,'进程号',os.getpid())
def func2():
global num
num += 500
print(num,'进程号',os.getpid())
if __name__ == '__main__':
print('kaishi')
print(num)
p1 = Process(target=func1)
p2 = Process(target=func2)
p1.start()
p2.start()
# p1.terminate()
# p2.terminate()
p1.join()
p2.join()
print('结束')
2.线程
- 有了进程为什么还需要线程
- 因为进程不能同一时间只能做一个事情
- 什么是线程
- 线程是操作系统调度的最小单位
- 线程是进程正真的执行者,是一些指令的集合(进程资源的拥有者)
- 同一个进程下的读多个线程共享内存空间,数据直接访问(数据共享)
- 为了保证数据安全,必须使用线程锁
- GIL全局解释器锁
- 在python全局解释器下,保证同一时间只有一个线程运行
- 防止多个线程都修改数据
- 线程锁(互斥锁)
- GIL锁只能保证同一时间只能有一个线程对某个资源操作,但当上一个线程还未执行完毕时可能就会释放GIL,其他线程就可以操作了
- 线程锁本质把线程中的数据加了一把互斥锁
- mysql中共享锁 & 互斥锁
- mysql共享锁:共享锁,所有线程都能读,而不能写
- mysql排它锁:排它,任何线程读取这个这个数据的权利都没有
- 加上线程锁之后所有其他线程,读都不能读这个数据
- mysql中共享锁 & 互斥锁
- 有了GIL全局解释器锁为什么还需要线程锁
- 因为cpu是分时使用的
- 死锁定义
- 两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去
from threading import Thread
def func1(man):
print('我是',man)
def func2(name):
print('我是',name)
if __name__ == '__main__':
print('主线程开始')
t1 = Thread(target=func1,args=('aa1',))
t2 = Thread(target=func2,kwargs={'name':'aa'})
t1.start()
t2.start()
t1.join()
t2.join()
print('主线程结束')
def func():
print('子线程开始')
for i in range(5):
print('线程',i)
time.sleep(0.1)
print('子线%s程结束'%i)
if __name__ == '__main__':
print('主线程开始')
t =Thread(target=func,daemon=True)
# t = Thread(target=func)
t.setDaemon(True)
t.start()
t.join()
print('主线程结束')
from threading import Thread
import threading
num = 0
lock1 = threading.Lock() #创建全局互斥锁
def func1():
lock1.acquire() # 上锁
global num #修改全局变量
for i in range(1000000):
num +=1
print('sum1',num)
lock1.release() #解锁
def func2():
lock1.acquire() # 上锁
global num #修改全局变量
for i in range(1000000):
num +=1
print('sum2',num)
lock1.release() #解锁
if __name__ == '__main__':
t1 = Thread(target=func1)
t2 = Thread(target=func2)
t1.start()
t2.start()
3.协程
- 什么是协程
- 协程微线程,纤程,本质是一个单线程
- 协程能在单线程处理高并发
- 线程遇到I/O操作会等待、阻塞,协程遇到I/O会自动切换(剩下的只有CPU操作)
- 线程的状态保存在CPU的寄存器和栈里而协程拥有自己的空间,所以无需上下文切换的开销,所以快、
- 为甚么协程能够遇到I/O自动切换
- 协程有一个gevent模块(封装了greenlet模块),遇到I/O自动切换
- 协程缺点
- 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上
- 线程阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
'''
协程
实现协程的方式
1、yield
2、greenlet
3、gevent
'''
import time
import greenlet
import gevent
import urllib.request
from gevent import monkey
# 用yield 实现协程
# def work1():
# while 1:
# print('真可爱')
# time.sleep(1)
# yield
# def work2():
# while 1:
# print('真坏')
# time.sleep(1)
# yield
#
# g1 = work1()
# g2 = work2()
# while 1:
# next(g1)
# next(g2)
# def consumer(): # consumer 消费者
# r = ''
# while True:
# n = yield r
# print('[消费者] Consuming %s...' % n)
#
#
# def produce(c): # produce 生产者
# c.send(None)
# for n in range(1, 6):
# print('[生产者] Producing %s...' % n)
# r = c.send(n)
# c.close()
#
#
# c = consumer()
# produce(c)
#-----用greenlet实现协程
# def work1():
# for i in range(5):
# print('姬小飞2000秒')
# time.sleep(0.2)
# g2.switch()
#
#
# def work2():
# for i in range(5):
# print('波老师')
# time.sleep(0.2)
# g1.switch()
#
#
# g1 = greenlet.greenlet(work1)
# g2 = greenlet.greenlet(work2)
# g1.switch() # 开启并切换到work1
# import gevent
#
#
# def jxf():
# print('姬小飞开始')
# gevent.sleep(4)
# print('姬小飞结束')
#
#
# def jhc():
# print('姬宏辰开始')
# gevent.sleep(1)
# print('姬宏辰结束')
#
#
# def lza():
# print('刘再昂开始')
# gevent.sleep(7)
# print('刘再昂结束')
#
#
# gevent.joinall([
# gevent.spawn(jxf),
# gevent.spawn(jhc),
# gevent.spawn(lza)
# ])```