Golang 之协程详解
Golang 线程和协程的区别备注:需要区分进程、线程(内核级线程)、协程(用户级线程)三个概念。
进程、线程 和 协程 之间概念的区别
对于 进程、线程,都是有内核进行调度,有 CPU 时间片的概念,进行 抢占式调度(有多种调度算法)
对于 协程(用户级线程),这是对内核透明的,也就是系统并不知道有协程的存在,是完全由用户自己的程序进行调度的,因为是由用户程序自己控制,那么就很难像抢占式调度那样做到强制的CPU 控制权切换到其他进程/线程,通常只能进行 协作式调度,需要协程自己主动把控制权转让出去之后,其他协程才能被执行到。
goroutine 和协程区别
本质上,goroutine 就是协程。 不同的是,Golang 在 runtime、系统调用等多方面对 goroutine 调度进行了封装和处理,当遇到长时间执行或者进行系统调用时,会主动把当前goroutine 的CPU (P) 转让出去,让其他 goroutine 能被调度并执行,也就是 Golang 从语言层面支持了协程。Golang的一大特色就是从语言层面原生支持协程,在函数或者方法前面加 go关键字就可 ...
协程切换的三种底层实现方式
1.setjmp/longjmpsetjmp 和 longjmp 是C语言中用于实现基本的协程的底层函数。它们允许在一个函数的执行过程中保存当前的执行状态(包括寄存器和栈信息),然后在之后的某个时间点恢复到这个状态,从而实现函数的非局部跳转。这两个函数通常用于实现基于栈的协程,但它们相对较底层,因此需要小心使用,以避免引入潜在的错误。
setjmp 函数用于保存当前执行状态,并将其存储在一个 jmp_buf 结构中。jmp_buf 可以看作是一个保存了程序执行状态的数据结构。
longjmp 函数用于从一个 jmp_buf 中恢复保存的执行状态,将程序跳转到之前保存的状态。这通常用于协程的切换,允许程序在不同的执行状态之间切换,实现协程的挂起和恢复。以下是一个简单示例,演示了如何使用 setjmp 和 longjmp实现一个简单的协程:
1234567891011121314151617181920#include <stdio.h>#include <setjmp.h>#include <unistd.h>jmp_buf buf;vo ...
从栈切换的角度理解进程和协程
函数在执行时,会在栈上创建栈帧,并将执行的上下文保存在栈帧中。栈切换在计算机系统设计中发挥着重要作用,特别是在并发程序中。多进程或多线程程序可以并发执行,充分利用多CPU 多核的计算资源,从而显著提升应用程序性能。理解进程和线程的切换过程对于优化并发程序至关重要。
操作系统为了避免频繁进入内核态,会将许多工作尽量放在用户态中进行。深入理解内核态和用户态的含义及其影响,有助于评估操作系统进入内核态的开销。实现这些切换的关键在于对执行单元的上下文环境进行切换,而这正是由栈这一核心数据结构支撑的。
掌握协程的基本知识有助于在使用各种协程库时理解其内部机制,进而编写出正确的 IO程序。同时,深入理解操作系统的用户态和内核态转换,对于架构设计中正确评估操作系统的性能开销也至关重要。在讨论执行单元的切换与栈的关系之前,需要给出它的准确定义。
什么是执行单元执行单元是指 CPU 调度和分派的基本单位,它是一个 CPU 能正常运行的基本单元。执行单元是可以停下来的,只要能把 CPU状态(其实就是寄存器的值)全部保存起来,等到这个执行单元再被调度的时候,就把状态恢复过来就行了。我们把这种保存状态,挂起, ...
python 协程详解
Python中的协程经历了很长的一段发展历程。其大概经历了如下三个阶段
最初的生成器变形yield/send
引入@asyncio.coroutine和yield from
在最近的Python3.5版本中引入async/await关键字
协程是什么协程,又称微线程,纤程。英文名Coroutine,是一种用户态的轻量级线程。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。
寄存器上下文和栈保存到其他地方
线程和进程的上下文切换是由内核管理的。协程则是在用户态下运行,它不依赖于内核的调度,而是由用户程序自行管理。因此,协程的上下文保存和恢复通常是由程序库(如 Python 的 asyncio 或 Go 的 goroutine 库)来处理的。
具体来说,协程的上下文和栈保存位置可以是
程序的堆内存:协程上下文和栈信息通常会保存在程序的堆内存中。每个 ...
系统的用户态与内核态
用户态和内核态的定位用户态和内核态的区分是在操作系统层面进行的。这两种状态是操作系统为了安全和管理而设计的。在操作系统中,内核态(Kernel Mode)是运行操作系统程序、操作硬件的状态,具有最高权限;而用户态(User Mode)是运行用户程序的状态,其权限受到限制。当用户程序需要操作系统帮助完成某些它没有权力和能力完成的工作时,就会通过系统调用陷入到内核态,由操作系统来完成相应的工作。
用户态用户态也被称为用户模式,是指应用程序的运行状态。在这种模式下,应用程序拥有有限的系统资源访问权限,只能在操作系统划定的特定空间内运行。用户态下运行的程序不能直接访问硬件设备或执行特权指令,所有对硬件的访问都必须通过操作系统进行。在用户态下,应用程序通过系统调用来请求操作系统提供的服务。例如,文件操作、网络通信等都需要通过系统调用来实现。当应用程序发出系统调用时,会触发上下文切换,将CPU的控制权交给操作系统内核,进入内核态。
内核态内核态也被称为内核模式或特权模式,是操作系统内核的运行状态。处于内核态的CPU可以执行所有的指令,访问所有的内存地址,拥有最高的权限。内核态下运行的程序可以访问系 ...
一个非常主流的web项目包结构-java
1234567891011121314151617181920212223242526272829303132333435363738io +- github +- xxyopen +- novel +- NovelApplication.java -- 项目启动类 | +- core -- 项目核心模块,包括各种工具、配置和常量等 | +- common -- 业务无关的通用模块 | | +- exception -- 通用异常处理 | | +- constant -- 通用常量 | | +- req -- 通用请求数据格式封装,例如分页请求数据 | | +- resp -- 接口响应工具及响应数据格式封装 | | +- util -- 通用工具 | | ...
vue3强制更新dom
12345import {getCurrentInstance, ComponentInternalInstance} from 'vue'const update = getCurrentInstance() as ComponentInternalInstance | nullupdate!.proxy!.$forceUpdate()
内嵌iframe去除白色边框和设置全屏占满
12345678<iframe id="reportIframe" frameborder="0" scrolling="auto" style="width: 100%; height: 100%" :src=""/>
iframe内嵌页面,监听iframe内容高度dom跨域问题
運用 postMessage 解決 iframe 與父層溝通的問題
问题描述当在iframe的父级监听iframe中的内容时候,如果内嵌的路由与父级的源不一致,会出现跨域问题。出现如下报错信息:
12345const iframe = document.querySelector("iframe");iframe.onload = () => { const iframeInner = iframe.contentWindow; console.log(iframeInner);};
12Uncaught DOMException: Failed to read a named property 'document' from 'Window': Blocked a frame with origin "http://localhost:1024" from accessing a cross-origin frame. at eval (
基於同源政策,如果 ...
python 操作 ftp
ftp_manager.py
123456789101112131415161718192021222324252627282930313233343536373839404142434445from ftplib import FTPclass FtpManager: host = "" username = "" password = "" def __init__(self): """连接到 FTP 服务器""" self.ftp = FTP(self.host) # 替换为你的 FTP 服务器地址 self.ftp.login(user=self.username, passwd=self.password) # 替换为你的用户名和密码 def list_files(self): """列举目录中的所有文件""" ...