进程
进程是系统进行资源分配和调度的一个独立单位,每个进程都有自己独立的内存空间。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销比较大,但相对比较稳定安全。
线程
线程是进程的一个实体,是cpu调度和分派的基本单位。线程主要通过共享内存,上下文切换很快,所以资源开销较少,但相比进程不够稳定,容易丢失数据。
协程
协程是一种用户态的轻量级线程。
进程,线程及协程开销最小的是协程,开销最大的是进程
线程的开销处于进程与协程之间,与进程相比不够稳定,容易丢失数据。
互斥锁(厕所门锁),信号量(钥匙扣)
1.以多进程形式,允许多个任务同时运行
2.以多线程形式,允许单个任务分成不同部分运行
3.提供协调机制,
一个程序可以有多个进程
一个进程可以有多个线程
一个线程可以有多个协程
进程是cpu进行资源分配和调度的独立单位,也就是一个cpu一次性只能执行一个进程
多任务是如何实现的?
1.使用多核cpu
2.进程高速交替执行
GIL
GIL是Python解释器(Cpython)时引入的概念,在JPython、PyPy中没有GIL。GIL并不是Python的语言缺陷。
全局解释锁
GIL存在原因
CPython在执行多线程的时候并不是线程安全的,为了线程间数据的一致性和状态同步的完整性。
GIL的弊端
- GIL对计算密集型的程序会产生影响。因为计算密集型的程序,需要占用系统资源。GIL的存在,相当于始终在进行单线程运算,这样自然就慢了。
- IO密集型影响不大的原因在于,IO,input/output,这两个词就表明程序的瓶颈在于输入所耗费的时间,线程大部分时间在等待,所以它们是多个一起等(多线程)还是单个等(单线程)无所谓的。
异步:
不按照顺序执行,并行执行。(使用多一些)
ps:可以理解为在不同的线程执行
串行:类似于同步,按照顺序执行
并行:类似于异步执行【执行任务的数量小于或者等于cpu的数量】
并发:任务的数量大于cpu的数量【不是真正的并行】,由CPU高速交替执行
同步:
按顺序执行代码
ps:可以理解成在同一个线程中执行
创建守护线程
import _thread
import time
import threading
def func(msg):
print(msg)
获取当前正在执行的线程
print(threading.current_thread().name)
def creat_thead():
_thead.start_new_thead(func,参数)
参数一:在子线程中执行的函数
参数二:子线程执行函数的时候需要的参数,传递参数的时候一定要以元组的方式传参。
守护线程:无论守护是否执行结束,只要主线程结束,守护线程都会自动结束。
第二种线程:
导入模块
import threading
def func(msg):
print(msg)
获取当前正在执行的线程
print(threading.current_thread().name)
def creat_thead():
t = threading.Thread(target=func,args=("hello world",))
t.start()
第三种线程:
若通过继承来创建线程,那么我们必须重写一个函数,这个函数就是run函数,在此函数中我们可以写在子线程中要执行的程序。此函数不需要我们自己手动调用,当我们启动线程的时候,会自动调用此方法。
导入模块
import threading
class MyThread(threading.Thread):
def __init__(self,msg):
super().__init__()
self.msg = msg
def run(self):
print("哈哈")
print(self.msg)
print(threading.current_thread().name)
if __name__ == '__main__':
t = MyThread("hello world")
t.start()
线程常用的函数及属性
t = threading.Thread(target=func,args=("hello",),name="helloname",daemon=False)
target:线程执行函数
args:函数需要的参数,必须以元组的方式传参
name:指定子线程的名字
daemon:设置是否为守护线程,默认为False,若为守护线程则为True
t.isAlive()
功能:判断线程是否还活着
t.getName() 获取线程的名字
t.setName() 设置线程的名字
t.start() 开启线程,线程准备就绪
t.isDaemon() 判断某个线程是否为后台线程
t.join([timeout]): 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout
6.获取线程ID
多个线程同时运行,是异步执行
会阻塞 等待t1线程执行完成后再继续往后执行
若多个线程想让其按顺序执行,则可以使用join() 的方法
cpu分配的时间片不足以完成一百万次的加法运算,
因此,数据还没有被保存,就被其他的线程打断了。
lock = threading.Lock()
在访问此变量之前我们要添加这把锁,当变量使用结束的时候,将这把锁释放即可。
lock.acquire() #上锁
lock.release() #释放锁
使用 with lock
死锁:
定义:是指一个资源多次调用,而多次调用对方都未能释放该资源就会造成一种互相等待的现象,若无外力作用,它们都将无法推进下去,此时称系统处于死锁状态或者系统产生了死锁。
使用递归锁来解决死锁的问题。
递归锁的实现原理:
在递归锁中不但存在lock还存在counter计数,每当acquire()一次锁,counter计数就进行
加1处理,每当release() 一次锁,counter计数减1处理,直到counter计数为0的情况下
所有线程重新去抢占资源。
import threading
import time
s = threading.Semaphore(5)
信号量的实现方式:
s = threading.Semaphore(5)
在内部有一个counter计数器,每当我们 s.acquire()一次,计数器就进行减1处理
每当 s.release()一次,计数器就进行加1处理,当计数器为0的时候其他线程的就处于
等待的状态counter的值就是同一时间可以开启线程的个数
建议使用with
取消安全认证
请求头
获取一个request对象
获取一个响应对象
参数一:请求对象
参数二:取消安全认证的上下文
从响应对象中读取数据
target:线程执行函数
args:函数需要的参数,必须以元组的方式传参
name:指定子线程的名字
daemon:设置是否为守护线程,默认为False,若为守护线程则为True
t.isAlive()
功能:判断线程是否还活着
t.getName()
功能:获取线程的名字
t.start()
功能:开启线程,线程准备就绪
t.isDaemon( )
功能:判断某个线程是否为后台线程
t.join()
功能:阻塞当前上下文环境
线程冲突:cpu分配的时间片不足以完成一百万次的加法运算,因此数据还没有被保存,就被其他线程打断勒
信号量
内置的一个计数器
宕机:程序无法从一个非正常的状态中恢复过来
导入 模块
import threading
信号量的实现方式:在内部有一个counter计数器,每当我们