什么是协程?协程和线程的区别

news2024/11/17 5:56:08

文章目录

  • 前置知识
    • 应用程序和内核
    • 阻塞和非阻塞
    • 同步和异步
    • 并发和并行
    • IO 发展历史
      • 同步编程
      • 异步多线程/进程
      • 异步消息 + 回调函数(响应式编程)
  • 协程
    • 协程基本概念
    • `go` 示例代码
    • 协程和线程的区别
  • 个人简介

前置知识

  • 在了解协程前,我们先理解一些相关的基本知识。

应用程序和内核

unix.jpg

  • 内核具有最高权限,可以访问受保护的内存空间,可以访问底层的硬件设备。而这些是应用程序所不具备的,但应用程序可以通过调用内核提供的接口来间接访问或操作。
  • 以一次网络 IO 操作为例,请求的数据会先被拷贝到系统内核的缓冲区(内核空间),然后再从内核缓冲区拷贝到应用程序的地址空间(用户空间)。这个过程包括两个阶段:
1、等待数据准备: 数据从网络接口读取并放入内核缓冲区。
2、拷贝数据: 数据从内核缓冲区复制到应用程序的用户空间。

阻塞和非阻塞

  • 从上面我们可以清楚的知道, 一次 IO 操作 操作流程分为两步:等待数据准备、拷贝数据,若等待数据准备过程是阻塞的,则我们称为阻塞操作;若不必等待数据准备完成,而是返回是否就绪标志,则称为非阻塞。

同步和异步

  • 用户线程发起 IO 操作,阻塞等待 IO 操作完成,则操作是同步的;若用户发起 IO 操作,不必等待操作完成,等待内核完成 IO 操作后通知用户线程,则为异步,如常见的 aio_read 函数

并发和并行

  • 并发(concurrency):逻辑上具备同时处理多个任务的能力。
  • 并行(parallesim):物理上在同一时刻执行多个并发任务,依赖多核处理器等物理设备。

IO 发展历史

  • 在没有协程的时代,处理 IO 操作我们一般使用下面三种方式:

同步编程

  • 应用程序阻塞等待IO结果(比如等待打开一个大的文件,或者等待远端服务器的响应)。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class SynchronousIO {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
优点:编程简单,方便理解
缺点:阻塞读取,效率低下,与 IO 无关的操作也需要等待 IO 完成

异步多线程/进程

  • 将IO操作频繁的逻辑、或者单纯的IO操作独立到一/多个线程中,业务线程与IO线程间靠通信/全局变量来共享数据。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AsynchronousMultiThreadIO {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(4);

        executor.submit(() -> {
            try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        executor.shutdown();
    }
}
优点:多线程处理,提高系统响应速度;充分利用 CPU 资源、避免阻塞其它业务
缺点:上下文切换成本较高,编程复杂度较高,需要管理大量线程

异步消息 + 回调函数(响应式编程)

  • 在响应式编程中,IO 操作是非阻塞的,并且通过回调函数来处理结果。

  • 示例代码(使用 CompletableFuture)

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;

public class AsynchronousCallbackIO {
    public static void main(String[] args) {
        CompletableFuture.runAsync(() -> {
            try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).thenRun(() -> System.out.println("File reading completed."));
    }
}
  • 示例代码(使用 Reactor):
import reactor.core.publisher.Mono;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class ReactiveIO {
    public static void main(String[] args) {
        Path path = Paths.get("example.txt");
        Mono.fromCallable(() -> Files.readString(path))
            .subscribe(content -> System.out.println(content),
                       error -> error.printStackTrace(),
                       () -> System.out.println("File reading completed."));
    }
}
优点:
1、相比多线程 IO,响应式编程的资源开销更低,能够更好地利用系统资源
2、响应式编程模型适合处理高并发、高吞吐量的应用,便于扩展和维护

缺点:
1、学习曲线陡峭:响应式编程需要理解异步编程和回调机制,对于初学者来说可能比较困难
2、调试复杂:由于异步操作的非顺序执行,调试和错误处理变得更加复杂

协程

协程基本概念

  • 维基百科定义:Coroutines are computer program components that generalize subroutines for non-preemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations. Coroutines are well-suited for implementing more familiar program components such as cooperative tasks, exceptions, event loops, iterators, infinite lists and pipes.
  • 中文翻译:协程是一种计算机程序组件,它通过允许多个入口点在特定位置暂停和恢复执行,将非抢占式多任务的子程序进行了一般化。协程非常适合实现更熟悉的程序组件,如协作任务、异常、事件循环、迭代器、无限列表和管道。
  • 简而言之:协程(Goroutines)是一种轻量级的并发编程模型,由编程语言或运行时环境管理,用于执行并发任务。与传统的操作系统线程相比,协程更轻量级,切换开销更小,因此在高并发场景中非常高效。协程在许多现代编程语言中都有实现,包括 Go、Python、JavaScript(在某种程度上通过异步函数和生成器)等。
  • 协程从一定程度来讲,可以说是“用同步的语义解决异步问题”,即业务逻辑看起来是同步的,但实际上并不阻塞当前线程(一般是靠事件循环处理来分发消息)。

go 示例代码

  • 下面是一个使用 Go 协程协作的示例,这个示例展示了如何使用 sync.WaitGroup 和 channel 来实现协程之间的协作:
package main

import (
	"fmt"
	"sync"
	"time"
)

// 定义一个 WaitGroup 以等待所有协程完成
var wg sync.WaitGroup

// 定义两个 channel 用于协程间的通信
var ch1 = make(chan int)
var ch2 = make(chan int)

func worker1() {
	defer wg.Done() // 在函数结束时减少 WaitGroup 计数
	for i := 0; i < 5; i++ {
		fmt.Println("Worker 1: Sending", i)
		ch1 <- i // 将数据发送到 ch1
		time.Sleep(500 * time.Millisecond)
	}
	close(ch1) // 关闭 channel,通知 worker2 没有更多数据
}

func worker2() {
	defer wg.Done() // 在函数结束时减少 WaitGroup 计数
	for {
		val, ok := <-ch1 // 从 ch1 接收数据
		if !ok {
			break // 如果 ch1 已关闭,退出循环
		}
		fmt.Println("Worker 2: Received", val)
		fmt.Println("Worker 2: Sending", val*val)
		ch2 <- val * val // 将数据发送到 ch2
		time.Sleep(500 * time.Millisecond)
	}
	close(ch2) // 关闭 channel,通知 main 没有更多数据
}

func main() {
	// 启动 worker1 和 worker2 协程
	wg.Add(2)
	go worker1()
	go worker2()

	// 在主协程中从 ch2 接收数据
	go func() {
		for val := range ch2 {
			fmt.Println("Main: Received", val)
		}
	}()

	wg.Wait() // 等待所有 worker 协程完成
}

协程和线程的区别

  • 协程属于用户级线程,线程属于内核级线程,线程的创建、上下文切换远比协程消耗更大。
  • 协程属于非抢占式,不会被其它协程所抢占,而是由开发者自己调度;线程属于抢占式,受到操作系统调度。
  • 协程的编码相比与多线程的编码更加复杂,但是协程大多数场景下更适合大并发任务。

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

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

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

相关文章

VBA数据库解决方案第十二讲:如何判断数据库中数据表是否存在

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…

平安养老险陕西分公司参加2024上半年省级单位驻富平帮扶团联席会

6月28日&#xff0c;平安养老险陕西分公司工会副主席武媛携驻村工作队赴富平县庄里镇永安村参加2024上半年度省级单位驻富平帮扶团联席会议。 会议由省委金融办副主任、省委金融工委委员李嘉辉及省委金融办选派挂职干部、富平县副县长席玮共同主持。 会上&#xff0c;席玮县长带…

全球AI新闻速递6.28

全球AI新闻速递 1.首款 Transformer 专用 AI 芯片 Sohu 登场。 2.钉钉&#xff1a;宣布对所有AI大模型厂商开放&#xff0c;首批7家接入。 3.华为联合清华大学发布《AI 终端白皮书》。 4.国家卫生健康委&#xff1a;推动AI技术在制定个性化营养、运动干预方案中的应用。 …

地下水电站3D虚拟仿真展示平台

借助先进的VR技术&#xff0c;我们将水电站的每一个角落、每一处细节都以三维全景的形式真实呈现。您可以自由穿梭于水电站的各个区域&#xff0c;无论是发电机组、巍峨的水坝&#xff0c;还是错综复杂的输水管道&#xff0c;都近在咫尺。感受水流的澎湃力量&#xff0c;聆听机…

中文TeX,各种数学符号和表格

\documentclass{article} \usepackage{amsmath,amssymb,amsfonts} \usepackage{CJKutf8} \begin{document}\begin{CJK}{UTF8}{gkai}%正文放在此行下与\end{CJK}之间就行你好, LaTeX!平方根 $\sqrt{x}$立方根 $\sqrt[3]{x}$分数的代码是 $\frac{a}{b}$求和的代码是 $\sum_{i1}^{…

自闭症儿童能不能用药

在星贝育园自闭症儿童康复学校&#xff0c;我们一直秉持着谨慎且保守的态度对待自闭症儿童的用药问题。我们坚定地认为&#xff0c;在大多数情况下&#xff0c;药物并非自闭症儿童康复的首选。 自闭症是一种神经发育障碍&#xff0c;其核心症状包括社交沟通障碍、重复刻…

API-元素尺寸与位置

学习目标&#xff1a; 掌握元素尺寸与位置 学习内容&#xff1a; 元素尺寸与位置仿京东固定导航栏案例实现bilibili点击小滑块移动效果 元素尺寸与位置&#xff1a; 使用场景&#xff1a; 前面案例滚动多少距离&#xff0c;都是我们自己算的&#xff0c;最好是页面滚动到某个…

快钱支付股东全部股权已被质押!

根据近期工商信息&#xff0c;第三方支付机构快钱支付清算信息有限公司&#xff08;简称“快钱支付”&#xff09;实际控股方快钱金融服务&#xff08;上海&#xff09;有限公司&#xff08;简称“快钱金融”&#xff09;&#xff0c;作为出质股权标的企业&#xff0c;被出质给…

MQTT协议详述

MQTT 概述 消息队列遥测传输&#xff08;英语&#xff1a;Message Queuing Telemetry Transport&#xff0c;缩写&#xff1a;MQTT&#xff09;&#xff0c;是基于发布&#xff08;Publish&#xff09;/订阅&#xff08;Subscribe&#xff09;范式的消息协议&#xff0c;位于…

qt QTreeView的简单使用(多级子节点)

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);setWindowTitle("QTreeView的简单使用");model new QStandardItemModel;model->setHorizontalHeaderLabels(QStringList() << "left&q…

解决OneDrive “拒绝访问文件” 问题

问题描述&#xff1a; 在尝试将其他文件拖入oneDrive或是打开OneDrive中的文件时。出现如下报错&#xff1a; 拒绝访问文件 无法访问XXXXXXX中的文件。可能已移动或删除了此文件&#xff0c;或者受制于文件权限而不能访问。 ERR_ACCESS_DENIED 解决办法&#xff1a; 1. 找到O…

统计学三学习笔记

一&#xff0c;t分布 二&#xff0c;置信区间 最终要用② n越大&#xff0c;s越小&#xff0c;置信区间越小 三&#xff0c;配对样本t检验 假如有两个族群&#xff1a;

2024-07-01_外语学习

文章目录 前言1、Los Angeles至于单个los 是什么意思&#xff1f;我们可以逐词翻译这个西班牙语句子 2. Extraneous non-props attributes (style) were passed to component but could not be automatically inherited because component renders fragment or text root nodes…

【UE5.1】Chaos物理系统基础——02 场系统的应用

目录 步骤 一、运用临时场&#xff08;外部张力&#xff09;破裂几何体集 二、使用构造场固定几何体集 步骤 在上一篇中&#xff08;【UE5.1】Chaos物理系统基础——01 创建可被破坏的物体&#xff09;我们已经创建了可被破碎的几何体集&#xff0c;在最后我们防止几何体集…

python(6)numpy的使用详细讲解

在numpy中&#xff0c;最基本的数据结构是数组&#xff0c;因此我们首先需要了解如何创建一个数组。numpy提供了多种数组创建方法&#xff0c;包括从列表或元组创建、从文件中读取数据、使用特定函数创建等。下面是一些常用的创建方法&#xff1a; 一、创建数组 1. 从列表或元…

【YOLOv5/v7改进系列】更换损失函数为CIOU、GIOU、SIOU、DIOU、EIOU、WIOUv1/v2/v3、Focal C/G/S/D/EIOU等

一、导言 在目标检测任务中&#xff0c;损失函数的主要作用是衡量模型预测的边界框&#xff08;bounding boxes&#xff09;与真实边界框之间的匹配程度&#xff0c;并指导模型学习如何更精确地定位和分类目标。损失函数通常由两部分构成&#xff1a;分类损失&#xff08;用于…

叮!云原生虚拟数仓 PieCloudDB Database 动态包裹已送达

第一部分 PieCloudDB Database 最新动态 支持动态配置查询簇 PieCloudDB 最新内核版本 v2.14.0 新增动态配置查询簇功能。PieCloudDB 动态配置查询簇功能实现可伸缩的并行化查询&#xff0c;可提升单个查询并行使用底层资源的能力&#xff0c;同时加快查询响应速度。 动态配…

【论文阅读】-- TimeNotes:时间序列数据的有效图表可视化和交互技术研究

TimeNotes: A Study on Effective Chart Visualization and Interaction Techniques for Time-Series Data 摘要1 介绍和动机2 文献2.1 时间序列数据探索2.1.1 数据聚合2.1.2 基于透镜2.1.3 基于布局 3 任务和设计3.1 数据3.2 领域表征3.3 探索、分析和呈现 4 TimeNotes4.1 布局…

制造型企业生产管理的技巧,你都用过哪些?

作为管理者&#xff0c;一谈到生产管理&#xff0c;你可能会想到很多生产过程中的问题&#xff1a;订单准交率不高、计划达成率不高、生产效率低、再制品太多、生产周期长等等一系列问题&#xff1b;如果你不仅仅是一名管理者&#xff0c;你还是一名企业主&#xff0c;你甚至经…