线程 死锁 信号量

进程

进程是系统进行资源分配和调度的一个独立单位,每个进程都有自己独立的内存空间。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销比较大,但相对比较稳定安全。

线程

线程是进程的一个实体,是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计数器,每当我们

猜你喜欢

转载自blog.csdn.net/weixin_45183510/article/details/93886883