首页 > 系统相关 >进程,线程和协程;为什么有了GIL锁还要互斥锁;多态和多态性;鸭子类型

进程,线程和协程;为什么有了GIL锁还要互斥锁;多态和多态性;鸭子类型

时间:2023-08-03 17:47:55浏览次数:41  
标签:__ 协程 多态性 worker 多态 互斥 线程 进程 gil

进程,线程和协程;为什么有了GIL锁还要互斥锁;多态和多态性;鸭子类型

为什么有了GIL锁还要互斥锁

1.GIL本身就是一个大的互斥锁
2.同一个进程下资源是共享的,也就是说多条线程可以操作同一个变量
3.多个线程可以操作同一个变量就会出现数据安全问题
4.临界区:指一段代码或一段程序片段,需要在同一时间只能被一个线程执行,所以多个线程操作临界区,会出现并发安全问题

# 错误的理解
-有了gil锁,同一时刻,只有一个线程执行,临界区代码,不也只有一个线程在执行吗?只有一个线程在执行,临界区就是安全的,不会出现数据错乱,所以没有必要再加互斥锁了

# 正确的解释
-gil锁释放不是我们控制的,比如在执行临界区中间,释放了,就会数据错乱问题

# 什么时候会释放gil锁?
1 线程遇到io
2 时间片轮转,时间片到了,就会自动切换

# 小案例解释
进程中有个变量a=0
    
    临界区:a+=1
    
    线程1要计算: a+=1  
    	1 线程1 拿到gil  
        2 读取a=0
        3 假设时间片到了,释放gil,释放cpu
      	4 等待下次被调度执行
        10 轮到它了,获取gil锁
        11 继续往下执行:计算a+1
        12 把结果赋值给a ,a=1
    	13 释放gil锁
     线程2要计算: a+=1 
        5 线程2获得了gil锁
        6 读取a=0
        7 计算a+1
        8 把结果赋值给a ,a=1
        9 释放gil锁
        
# 互斥锁保证数据安全
    a=0
    线程1要计算: a+=1  
    	1 线程1 拿到gil  
        # 加锁
        2 读取a=0
        3 假设时间片到了,释放gil,释放cpu
      	4 等待下次被调度执行
        
        7 轮到它了,获取gil锁
        8 继续往下执行:计算a+1
        9 把结果赋值给a ,a=1
    	10 释放gil锁
     线程2要计算: a+=1 
        5 线程2获得了gil锁
        #获取锁,获取不到
        6 释放gil锁
        11 获得gil锁
        
        #加锁
        12 读取a=0
        13 计算a+1
        14 把结果赋值给a ,a=1
        15 释放锁
        16 释放gil锁
    
    # gil锁并不锁住临界区,临界区需要我们自己用互斥锁加锁
    

进程,线程和协程

进程、线程和协程是并发编程中常见的三种并发执行方式。它们在代码中的体现略有不同:

# 1. 进程:
- 进程是操作系统分配资源的最小单位。一个应用程序运行起来至少有一个进程,进程管理器中就可以看到一个个的进程。每个进程都有自己独立的地址空间,相互之间不会干扰。
# 开启多进程两种方式
-1 写一个类,继承Process,重写类的run方法---》实例化得到对象,对象.start 开启了进程
-2 通过Process类实例化得到一个对象,传入任务 ,调用对象.start 开启了进程
import multiprocessing

def worker():
    print("This is a worker process.")

if __name__ == "__main__":
    process = multiprocessing.Process(target=worker)
    process.start()
    process.join()


# 2. 线程:
- 线程是操作系统调度的最小单位。多个线程共享同一个进程的地址空间,可以直接访问共享资源,一个进程下至少有一个线程。
# 开启线程两种方式
-1 写一个类,继承Thread,重写类的run方法---》实例化得到对象,对象.start 开启了进程
-2 通过Thread类实例化得到一个对象,传入任务 ,调用对象.start 开启了进程

import threading

def worker():
    print("This is a worker thread.")

if __name__ == "__main__":
    thread = threading.Thread(target=worker)
    thread.start()
    thread.join()

class PrintNumbersThread(threading.Thread):
  def run(self):
    for i in range(1,11):
      print(i)
      
t = PrintNumbersThread()
t.start()
    

# 3. 协程:
- 协程是一种轻量级的线程,单线程下的并发。协程是程序层面的任务切换,而不是操作系统的抢占式调度。
# 开启协程两种方式
- 早期:借助于第三方gevent,基于greenlet写的
- async 和 await 关键字,不借助于第三方,开启协程asyncio包
		- 必须写在一个函数前, async def task()----》这个函数执行的结果是协程函数
		-await 只要是io操作的代码,前面必须加 await

import asyncio

async def worker():
  	a+=2
  	await 遇到io
    a+=2=
    print("This is a worker coroutine.")

if __name__ == "__main__":
    asyncio.run(worker())


你在哪里用过

-我一般遇到计算密集型的操作,我会开多进程,io密集型的操作,我一般开多线程
-闲来无事,爬别人数据,喜欢开多线程,爬虫io居多
-程序中,异步做一件事情,也可以开多线程
        比如一个视图函数,异步的吧数据写的文件中
        异步的发送钉钉通知
        异步的发送邮件
-但实际上,在项目中,不需要我们开启进程线程,可以借助于第三方的框架比如celery就可以做异步的操作
        而celery的worker,就是进程线程架构
-django框架,是支持并发,我们没有开启多进程和多线程,但是符合uwsgi的web服务器在进入djagno框架之前,开启了进程和线程来执行视图函数


# 进程间通信需要使用管道,消息队列实现
# 线程间通信用什么?
# 协程会出现并发安全的问题吗?

什么是鸭子类型

1 鸭子类型是python语言面向对象中的一个概念

# 面向对象三大特性
继承封装和多态

# 多态和多态性
-多态指的是同一类食物的多种形态,现实生活中水可以是冰、水、水蒸气,动物可以是人、狗、猪;程序中,一个Animal类可以是子类Human、Dog、Pig。
-多态性是不考虑对象具体类型的情况下使用对象,在程序中
		-len()内置函数---》传参数:字符串对象,列表对象,字典对象
-为什么能这样用?就是因为多态的存在
    -字符串,列表,字典----》属于同一类事物---》有长度的这一类事物

# 鸭子类型
-走路像鸭子,说话像鸭子,我们就可以叫它叫鸭子
-解释:鸭子类型是python面向对象中描述接口的一个概念,区分与其他编程语言,
-比如java:实现接口,必须显示地继承一个接口
-而python:实现接口,遵循鸭子类型,不需要显示地继承一个接口(类),只要类中有对应的属性跟方法,我们就称这几个类的对象为同一种类型

举例:
Python 的迭代器协议并不要求对象继承特定的接口或基类,只要对象实现了 __iter__() 和 __next__() 方法,它就可以被视为一个迭代器并可以用于 for 循环中。这符合了鸭子类型的思想,关注对象的行为而不是具体的类型。
或者说没有继承相同的父类,但是具有相同的方法,这2个类就属于同一个类型

标签:__,协程,多态性,worker,多态,互斥,线程,进程,gil
From: https://www.cnblogs.com/10086upup/p/17603978.html

相关文章

  • 为什么有了gil锁还要互斥锁、 进程,线程和协程 、什么是鸭子类型
    目录1为什么有了gil锁还要互斥锁互斥锁保证数据安全2进程,线程和协程在哪用过3什么是鸭子类型1为什么有了gil锁还要互斥锁gil:全局解释器锁,线程要执行,必须先获得到gil锁,才能执行互斥锁:为了保证多线程并发操作数据(变量)而设置的锁,保证在加锁和释放锁之间,其他线程不能操作gi......
  • C++逆向分析——多态和虚表
    虚表上一章了解了多态,那么我们来了解一下多态在C++中是如何实现的。了解本质,那就通过反汇编代码去看就行了,首先我们看下非多态的情况下的反汇编代码:然后再来看下多态情况下的反汇编代码:很明显这里多态的情况下会根据edx间接调用,而非多态则会直接调用。那么我们来看下间接调用的流程......
  • 多态性
    多态性引入:传统的方法(形参为不同类,就要新建不同的方法)代码复用性不高,不利于代码维护多(多种)态(状态):方法或对象具有多种形态多态的具体体现:方法的多态方法的重载和重写都体现了多态对象的多态对象的多态一个对象的编译类型和运行类型可以不一致,编译类型在定义对象时就......
  • 何为多态——和抽象又有什么关系
    到底什么是多态?面向对象三大特征:封装、继承、多态前面两个应该比较好理解,顾名思义,那最后这个多态到底是什么?我最近也看了一些相关的文章,但是可能因为水平尚浅,不是很能理解所以想自己总结一下,不一定完全正确,欢迎大家提出意见我认为多态这两个字,可以解释为多个形态多态其实是建......
  • Java 多态
    Java多态1.多态方法或对象具有多种形态。是面向对象的三大特征之一,多态是建立在封装、继承基础之上的2.多态的实现:方法的重载中,使用不同的形参调用方法体现出了多态方法的重写中,使用父类或子类的对象调用方法体现出了多态对象的多态:对象的编译类型与运行类型可以不一样......
  • 互斥锁
    在Python中,可以使用互斥锁(Mutex)来实现线程之间的互斥访问,保证共享资源的安全性。互斥锁可以确保在任何时刻只有一个线程可以持有锁,并且其他线程必须等待锁的释放才能继续执行。步骤1. 创建互斥锁对象:lock=threading.Lock()通过threading.Lock()函数创建一个互斥锁对象。......
  • Java并发(十四)----悲观互斥与乐观重试
    1.悲观互斥互斥实际是悲观锁的思想例如,有下面取款的需求interfaceAccount{  //获取余额  IntegergetBalance();​  //取款  voidwithdraw(Integeramount);​  /**  *方法内会启动1000个线程,每个线程做-10元的操作  *如......
  • c++学习:封装、继承、多态
    c++是面向对象的编程语言,相对于c具有封装、继承、多态的特点。封装定义:封装就是将对象的属性和行为封装起来,形成一个有机的整体,其载体就是类。类通常对客户隐藏其实现细节,这就是封装的思想,就比如我们使用一个库函数时,我们只需要知道它的作用就可以了,没必要去了解它的内部工......
  • java中关于多态的理解
    多态:是同一个行为具有多个不同表现形式或形态的能力。在代码的运用中主要是关于子类中方法的重写,实现了同一个父类接口可以进行不同子类中重写的方法publicclassGeometricOject{//父类publicdoublefindArea(){return0.0;}}publicclassCircleext......
  • Day05-22 多态
    多态即同一方法可以根据发送对象的不同而采用多种不同的行为方式一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多(父类,有关系的类)多态存在的条件有继承关系子类重写父类方法父类引用指向子类对象注意:多态是方法的多态,属性没有多态性。ins......