网络通信与并发编程(七)GIL、协程

news2024/11/6 21:26:36

GIL、协程

文章目录

  • GIL、协程
  • 一、GIL
  • 二、协程

一、GIL

GIL本质就是CPython解释器中的一把互斥锁。那既然是互斥锁,原理都一样,都是让多个并发线程同一时间只能有一个执行,以此确保共享数据的安全性。有了GIL的存在,同一进程内的多个线程同一时刻只能有一个在运行,意味着在Cpython中一个进程下的多个线程无法实现并行。这也意味着CPython中是无法利用cpu的多核优势的。
简单来讲GIL可以被比喻成执行权限,同一进程下的所有线程要想执行都需要先抢执行权限。

注:CPython是python解释器实现的一种方式,另外还有JPython、PyPy、Psyco等等,只有CPython才有GIL锁,并且大部分环境下默认的python解释器就是CPython。

首先我们需要明确一点,当我们运行py文件时,不光会产生一个主进程(主线程)以及子线程来执行这个py文件的代码,同时解释器也会产生一些解释器级别的线程去完成相关的任务(例如垃圾回收线程)。而解释器中的数据和py文件中的数据又是共享的,所以必须要一种锁来确保多个线程在修改数据时数据的安全性,这就是GIL锁存在的原因。

下面举个具体的例子:假如我们执行py文件生成了一个主进程,同时主进程又产生了三个子线程,则python的执行过程大致如下图所示。
在这里插入图片描述
首先主进程、子线程和垃圾回收机制线程会抢GIL锁,只有抢到GIL锁的线程才能执行内部代码并有权修改解释器的数据。需要注意的是子线程也是要抢GIL锁后才能执行的,如果子线程抢到GIL锁后发现需要修改的数据被mutex锁上了,子线程会进入阻塞状态,然后解释器会回收子线程的GIL锁。

问题:既然有了GIL为什么还要设置自定义的互斥锁呢?
GIL锁的是解释器的数据,自定义互斥锁锁的是用户的数据。例如用户创建三个线程修改文件中的某个数据,文件中的数据属于用户自己的数据不归解释器管,所以想要文件数据能被安全的修改必须加上自定义的互斥锁。

由于CPython的多线程无法使用cpu的多核优势问题,这在里再次强调一些python中多线程和多进程的选择问题:

  • (cpu多核情况下)若执行的任务是cup密集型的(大量计算任务),则使用多进程。因为python中的多线程无法使用多核cpu的优势,为了充分发挥多核cpu的计算力则需要使用多进程。
  • 若执行任务是I/O密集型的(如网络通信等等),则使用多线程。I/O密集型任务涉及大量的I/O操作,而多个进程间的来回切换对比于多个线程之间而言消耗更多时间与资源。

GIL的释放和自定义互斥锁有何不同?
GIL相当于执行权限,会在遇到I/O或者线程运行时间过长时被解释器回收。自定义互斥锁需要手动释放。

二、协程

协程也就是单线程实现并发效果,其本质是在应用程序里控制多个任务的切换并保存状态。
协程的优点:应用程序级别速度要远远高于操作系统的切换(开进程和线程都需要向操作系统申请)
协程的缺点:多个任务一旦有一个阻塞没有切换,整个线程都阻塞在原地,线程内的其他的任务都不能执行了。

协程的实现:为了实现单线程的并发效果,必须要时时检测线程内的I/O操作,遇到I/O操作立马切换其他任务以免阻塞影响运行效率。协程的难点也就在如何让程序在用户层面(不依靠操作系统)就能检测代码中的I/O操作。

问题:cpu并发运行时出现遇到I/O操作或者单个任务运行时间过长/遇到优先级更高的任务这两种情况都会进行切换,为什么协程遇到后者不切换呢?
cpu后面这种情况的切换只是为了让所以的任务都能雨露均沾。当任务为计算型时,后面的切换会降低任务的效率。所以协程只有遇到I/O时才进行切换。

为了实现程序内对I/O操作的检测,需要使用gevent模块,可以使用pip install gevent命令下载该模块。

#monkey.patch_all()为一个补丁,打上该补丁后gevent可以检测非gevent内置的I/O操作
#monkey.patch_all()需要放在最前面
from gevent import monkey,spawn;monkey.patch_all()
#gevent模块中spawn开启的是假线程,可以用current_thread查看假线程的名称
from threading import current_thread
import time

def eat():
    print('%s eat 1' %current_thread().name)
    #模拟I/O操作
    time.sleep(3)
    print('%s eat 2' %current_thread().name)

def play():
    print('%s play 1' %current_thread().name)
    #模拟I/O操作
    time.sleep(1)
    print('%s play 2' %current_thread().name)

#开启协程,若传入的函数有参数,需在spawn函数中传入
#如spawn(eat,1,2,t=3)
g1=spawn(eat)
g2=spawn(play)

print(current_thread().name)
#等待协程运行完毕,不写的话主进程代码结束协程的代码会被强制结束
#下方的代码可以简写为gevent.joinall([g1,g2])
g1.join()
g2.join()
#如何传入的函数有返回值,可以通过g1.value得到返回值

用协程实现socket并发:(服务端版)

from gevent import monkey,spawn;monkey.patch_all()
from socket import *
import gevent

def talk(conn,addr):
    try:
        while True:
            res=conn.recv(1024)
            print('client %s:%s'%(addr[0],addr[1]))
            conn.send(res.upper())
    except:
        conn.close()

if __name__=='__main__':
    s=socket(AF_INET,SOCK_STREAM)
    s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    s.bind(('127.0.0.1',8080))
    s.listen(5)
    while True:
        conn,addr=s.accept()
        gevent.spawn(talk,conn,addr)
        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2229114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6. 线程池实现

WebServer::thread_pool() 方法用于创建并初始化线程池,为服务器的并发处理能力提供支持。在 Web 服务器中,线程池用于管理多个工作线程,这些线程负责处理客户端的 HTTP 请求,以确保服务器可以同时处理多个并发请求,而…

基于Java的茶产品销售平台系统【附源码】

基于Java的茶产品销售平台系统 效果如下: 系统首页界面 用户登录界面 茶叶信息界面 在线客服界面 购物车界面 管理员登录界面 管理员功能界面 茶叶类型管理界面 研究背景 在当今社会,人们的生活节奏逐渐加快,人们对经济的要求逐渐降低&…

AI代币是什么?AI与Web3结合的未来方向在哪里?

近两年随着人工智能的崛起,AI已经渗透到制造业、电商、广告、医药等各个行业,加密货币领域也不例外,人工智能与区块链的融合,让我们看到了独特的数字资产 — AI加密代币。 它的流行始于2022年底,随着OpenAI智能聊天机…

Linux下MySQL8.x的编译安装与使用

Linux下MySQL的安装与配置 1. 安装环境初始化 1.1 查看是否安装过MySQL 如果使用rpm安装, 检查一下RPM PACKAGE rpm -qa | grep -i mysql # -i 忽略大小写 # 或者 yum list installed | grep mysql如果存在mysql-libs的旧版本包,显示如下 #存在 [rootlocalhost ~]…

如何在不安装WDK的情况下快速安装DevCon.exe?

你已经找到这里了,想必目的已经很清晰了,就是想要实现不安装WDK,又想使用Devcon.exe,那么往下看就对了。 这里直接上GitHub链接:https://github.com/Drawbackz/DevCon-Installer 考虑到网络环境,这里提供CS…

CSP/信奥赛C++刷题训练:经典二分例题(3):洛谷P8814[CSP-J 2022] 解密

CSP/信奥赛C++刷题训练:经典二分例题(3) [CSP-J 2022] 解密 题目描述 给定一个正整数 k k k,有 k k k 次询问,每次给定三个正整数 n i , e i , d i n_i, e_i, d_i ni​,ei​,di​,求两个正整数 p i , q i p_i, q_i pi​,qi​,使 n i = p i q i n_i = p_i \times…

git修改用户名与查看git的账号与密码

git修改用户名与查看git的账号与密码 文章目录 git修改用户名与查看git的账号与密码修改idea中代码提交的用户名查看git的账号与密码 修改idea中代码提交的用户名 1、打开您的IDEA,点击打开最下方的Terminal终端 2、输入以下命令,并回车执行 查看当前…

linux 安装php扩展:xlswriter

这里以xlswriter扩展为例 进入官方扩展:https://pecl.php.net查询自己php对应版本的扩展包 下载扩展 wget https://pecl.php.net/get/xlswriter-1.5.5.tgz 解压扩展 tar -zxvf xlswriter-1.5.5.tgz 进入扩展目录 cd xlswriter-1.5.5 查找对应php版本的phpiz…

解决电脑突然没有声音

问题描述:电脑突然没有声音了,最近没有怎么动过系统,没有安装或者卸载过什么软件,也没有安装或者卸载过驱动程序,怎么就没有声音了呢? 问题分析:仔细观察,虽然音量按钮那边看不到什…

php命令执行的一些执行函数----以ctfshow靶场为解题思路

PHP命令执行 一招鲜,吃遍天 cshow_source("flag.php"); cinclude($_GET[1]); cinclude("flag.php");var_dump(get_defined_vars()); web30: 这道题目过滤了flag,system,php。 那么我们 解法1:passthru ?cpassthru(…

mathorcup2024台风 我all in ai

三个问题,力大砖飞。 不建物理模型,直接all in好吧 第一个故意无监督 第二个LSTMCNN注意力,刚好时间空间 第三个在第二个上加了个transfomer ,然后LSTM变双向,增加层数(基线模型选的经验公式,少…

详细分析与梳理Java基础中的重点知识:String类 ,Java字符串String类入门,剖析String类底层机制

一、什么是String类? 众所周知,String类代表字符串类型。Java中所有被双引号包裹的字符串都是String类的对象。 (比如:"zhangsan" , "lisi" , "博主是帅哥" , "123Abc"......&#xff0…

【C/C++】模拟实现strlen

学习目标: 使用代码模拟实现strlen。 逻辑: strlen 需要输入一个字符串数组类型的变量,并且返回一个整型类型的数据。strlen 需要计算字符串数组有多少个元素。 代码1:使用计数器 #define _CRT_SECURE_NO_WARNINGS 1 #include&…

Java面试经典 150 题.P55. 跳跃游戏(009)

本题来自:力扣-面试经典 150 题 面试经典 150 题 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台https://leetcode.cn/studyplan/top-interview-150/ 题解: class Solution {public boolean canJump(int[] nums) {int…

梁山派入门指南2——滴答定时器位带操作按键输入

梁山派入门指南2——滴答定时器&位带操作&按键输入 1. 滴答定时器1.1 滴答定时器简介1.2 相关寄存器1.3 固件库函数 2. 位带操作2.1 位带操作介绍2.2 位带操作的优势2.3 支持位带操作的内存地址2.4 位带别名区地址的计算方式2.5 位带操作使用示例 3 按键输入3.1 独立按…

RHCE--4

第四章 web服务器 web服务器简介 www可以结合文字、图形、影像以及声音等多媒体,并通过可以让鼠标单击超链接的方式将信息以Internet传递到世界各处去。 www所用的协议:Hyper Text Transport Protocol,HTTP,超文本传输协议。 ww…

C++ | Leetcode C++题解之第515题在每个树行中找最大值

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> largestValues(TreeNode* root) {if (!root) {return {};}vector<int> res;queue<TreeNode*> q;q.push(root);while (!q.empty()) {int len q.size();int maxVal INT_MIN;while (…

如何安装和使用PowerDesigner

教程目录 一、安装二、使用 一、安装 1、启动安装程序。 2、Trial&#xff0c;然后Next。 3、选PRC&#xff0c;同意协议&#xff0c;Next。 4、设置安装路径&#xff0c;Next。 5、Next。 6、全选&#xff0c;Next。 7、Next。 8、Next。 9、等待安装。 10、…

人工智能生产力悖论:为什么大多数人没用上AI工具?

真正的障碍不是技术&#xff0c;而是思考的时间: 虽然像ChatGPT这样的工具确实有潜力带来变革&#xff0c;但我接触的大多数人几乎不用它。就算用的&#xff0c;也只是用来做些总结之类的小活儿。而在这些用户里&#xff0c;只有大约5%的人订阅了高级版&#xff0c;这意味着真…