首页 > 其他分享 >容易混淆的同步、异步、阻塞、非阻塞

容易混淆的同步、异步、阻塞、非阻塞

时间:2023-09-12 19:44:06浏览次数:31  
标签:异步 同步 混淆 阻塞 用户 线程 内核

同步&异步

同步和异步指的是:当前线程是否需要等待方法调用执行完毕。

比如你调用一个搬运一百块石头的方法:

同步指的是调用这个方法,你的线程需要等待这一百块石头搬完,然后得到搬完了的结果,接着再继续执行剩下的代码逻辑。

//同步方式
result = 搬一百块石头();
//需等待搬完的结果,才能执行下面的逻辑
if(result) {
石头搬完了发工资();
}
计算下一次搬石头的任务();

异步指的是调用这个方法,立马就直接返回,不必等候这一百块石头还未搬完,可以立马执行后面的代码逻辑,然后利用回调或者事件通知的方式得到石头已经搬完的结果。

//异步方式
搬一百块石头({
    //回调
 石头搬完了发工资();
});
//不必等待石头搬完,立马执行下面的逻辑
计算下一次搬石头的任务();

可以很直观的看出,同步和异步就是调用方式的不同,这使得我们的编码方式也有所不同。

在异步调用下的代码逻辑相对而言不太直观,需要借助回调或事件通知,这在复杂逻辑下对编码能力的要求较高。而同步调用就是直来直去,等待执行完毕然后拿到结果紧接着执行下面的逻辑,对编码能力的要求较低,也更不容易出错。

所以你会发现有很多方法它是异步调用的方式,但是最终的使用还是异步转同步。

比如你向线程池提交一个任务,得到一个 future,此时是异步的,然后你在紧接着在代码里调用 future.get(),那就变成等待这个任务执行完成,这就是所谓的异步转同步,像 Dubbo RPC 调用同步得到返回结果就是这样实现的。

阻塞&非阻塞

阻塞和非阻塞指的是:当前接口数据还未准备就绪时,线程是否被阻塞挂起。

何为阻塞挂起?就是当前线程还处于 CPU 时间片当中,调用了阻塞的方法,由于数据未准备就绪,则时间片还未到就让出 CPU。

所以阻塞和同步看起来都是等,但是本质上它们不一样,同步的时候可没有让出 CPU。

而非阻塞就是当前接口数据还未准备就绪时,线程不会被阻塞挂起,可以不断轮询请求接口,看看数据是否已经准备就绪。

至此我们可以得到一个结论:

  • 同步&异步指:当数据还未处理完成时,代码的逻辑处理方式不同。
  • 阻塞&非阻塞指:当数据还未处理完成时(未就绪),线程的状态。
    所以同步&异步其实是处于框架这种高层次维度来看待的,而阻塞&非阻塞往往针对底层的系统调用方面来抉择,也就是说两者是从不同维度来考虑的。

再结合 I/O 来看

前提:程序和硬件之间隔了个操作系统,而为了安全考虑,Linux 系统分了:用户态和内核态

在这个前提下,我们再明确 I/O 操作有两个步骤:

  1. 发起 I/O 请求
  2. 实际 I/O 读写,即数据从内核缓存拷贝到用户空间

阻塞 I/O 和非阻塞 I/O。按照上文,其实指的就是用户线程是否被阻塞,这里指代的步骤1(发起I/O请求)。

  • 阻塞 I/O,指用户线程发起 I/O 请求的时候,如果数据还未准备就绪(例如暂无网络数据接收),就会阻塞当前线程,让出 CPU。
  • 非阻塞 I/O,指用户线程发起 I/O 请求的时候,如果数据还未准备就绪(例如暂无网络数据接收),也不会阻塞当前线程,可以继续执行后续的任务。

可以发现,这里的阻塞和非阻塞其实是指用户线程是否会被阻塞。

同步 I/O 和异步 I/O。按照上文,我们可以得知这就是根据 I/O 响应方式不同而划分的。

  • 同步 I/O,指用户线程发起 I/O 请求的时候,数据是有的,那么将进行步骤2(实际 I/O 读写,即数据从内核缓存拷贝到用户空间),这个过程用户线程是要等待着拷贝完成。

  • 异步 I/O,指用户线程发起 I/O 请求的时候,数据是有的,那么将进行步骤2(实际 I/O 读写,即数据从内核缓存拷贝到用户空间),拷贝的过程中不需要用户线程等待,用户线程可以去执行其它逻辑,等内核将数据从内核空间拷贝到用户空间后,用户线程会得到一个“通知”。

再仔细思考下,在 I/O 场景下同步和异步说的其实是内核的实现,因为拷贝的执行者是内核,一种是同步将数据拷贝到用户空间,用户线程是需要等着的。一个是通过异步的方式,用户线程不用等,在拷贝完之后,内核会调用指定的回调函数。

如果不理解上面,就只需记住:

  • 同步I/O:指的是用户线程会需要等待步骤 2 执行完毕。

  • 异步I/O:指的是用户线程不需要等待步骤 2 执行。
    好了,如果以上的概念你都已经理解了的话,那么平日里我们所说的同步阻塞I/O,同步非阻塞I/O等其实就是把上面的两个步骤合起来看,应该不难理解。

总结一下,关于 I/O 的阻塞、非阻塞、同步、异步:

  • 阻塞和非阻塞指的是发起 I/O 请求后,用户线程状态的不同,阻塞I/O在数据未准备就绪的时候会阻塞当前用户线程,而非阻塞 I/O 会立马返回一个错误,不会阻塞当前用户线程。
  • 同步和异步是指,内核的 I/O 拷贝实现,当数据准备就绪后,需要将内核空间的数据拷贝至用户空间,如果是同步 I/O 那么用户线程会等待拷贝的完成,而异步 I/O则这个拷贝过程用户线程该干嘛可以去干吗,当内核拷贝完毕之后会“通知”用户线程。

要注意,不同场景下同一个名词意义可能不同。我这篇关于同步、异步、阻塞、非阻塞这几个概念是基于 I/O 场景下讲的。

标签:异步,同步,混淆,阻塞,用户,线程,内核
From: https://www.cnblogs.com/weicheng0/p/17697636.html

相关文章

  • 代码混淆和加固,保障应用程序的安全性
    摘要:本文将详细介绍iOS技术博主在保护应用程序代码安全方面的两种重要方式:代码混淆和代码加固。通过代码混淆和加固,博主可以有效防止他人对应用程序进行逆向工程和篡改,提高应用程序的安全性。引言:作为iOS技术博主,保护自己的代码免受不良行为的侵犯是非常重要的。为了确保代码的安......
  • 阻塞IO/非阻塞IO
    阻塞I/O(BlockingI/O):在阻塞I/O模式下,当程序执行一个I/O操作(如读取文件、网络通信等)时,它会等待直到该操作完成才会继续执行下一步操作。在等待期间,程序的执行会被暂停,无法执行其他任务,直到I/O操作完成或者发生超时。阻塞I/O通常较容易使用和理解,但可能会导致应用程序在高负载或......
  • android 混淆proguard_rule
    #设置混淆的压缩比率0~7-optimizationpasses5#混淆时不使用大小写混合,混淆后的类名为小写-dontusemixedcaseclassnames#混淆时不记录日志-verbose#代码优化-dontshrink#保留注解不混淆-keepattributes*Annotation*,InnerClasses#避免混淆泛型-keepattributesSignatu......
  • 深入了解Python协程与异步编程
    Python是一门强大的编程语言,提供了多种方式来处理并发和异步编程。在本博客中,我们将深入探讨Python中的协程(coroutines)和异步编程的重要性。什么是协程?协程是一种轻量级的线程,允许在一个线程中执行多个任务,而无需线程切换的开销。在Python中,协程通过asyncio库来实现。importasy......
  • 针对JavaScript混淆加密,JShaman推出新功能
    JShaman英文版在最新的一次更新时,增加了新功能:JavaScript代码混淆加密完成后,可以显示各功能耗时、处理的AST节点数量,以此可知对代码做了哪些保护处理。如上图所示,在此例中,对代码共进行了23项混淆加密,JSON数据加密8350处、字符串加密189669处、15222次平展控制流、30722处变量名修改......
  • 并行编程(二)Julia中的顺序和异步编程
    概述这节课的主要目标是开始使用Julia编程,实现并行算法,本次课程中,特别关注语言的部分(函数式和异步编程)。 学习目标运行Julia代码安装Julia软件包编写连续的Julia代码使用Julia的函数式编程功能使用Julia的异步编程功能 WhyJulia?与高性能计算相关的课程通常使用C、C......
  • live555流媒体服务器解决客户端异常掉线后导致服务端通道阻塞的问题
    live555在Linux环境下会因为客户端异常掉线后,偶现导致部分通道不能再被访问的问题,我们描述一下这个问题修复的过程。本来是分析服务端CLOSE_WAIT的问题,在调试的过程中,却又发现了阻塞,认真分析了live555的事件调用流程后,发现只要从客户端收到数据,就会执行GenericMediaServer::Clien......
  • Python FastAPI 异步获取 Neo4j 数据
    前提条件先往Neo4j里,准备数据参考:https://www.cnblogs.com/vipsoft/p/17631347.html#创建传承人搭建FastAPI项目:https://www.cnblogs.com/vipsoft/p/17684079.html改造utils/neo4j_provider.py增加了暴露给外面调用的属性,同时提供了同步和异步执行的驱动#!/usr/bin/py......
  • Oracle为什么写阻塞读导致Buffer Busy Waits
     Oracle为什么写阻塞读导致BufferBusyWaits 这之前需要了解在内存中定位并读取一个buffer的流程,先看看为什么读不阻塞写。 读不阻塞写:假设会话s1在读取dbbuffercache中读取需要的buffer过程中,会获取CBCLatch后查找定位buffer后,以共享S模式获取BH(BufferHeader)的Buff......
  • [个人笔记][C#]异步调用控制流的一些测试结论
    await调用逻辑总结如下:调用线程A执行到await时,在await处返回并继续执行调用点后面的代码,await处新开一个线程B执行task线程B执行完task后继续执行await后面的代码如果再次遇到await,线程B在await处返回,新开一个线程C执行task线程C执行完task后继续执行await后面的代码"新开......