当前位置: 首页 > news >正文

嵌入式Linux应用开发-驱动大全-第一章同步与互斥③

嵌入式Linux应用开发-驱动大全-第一章同步与互斥③

  • 第一章 同步与互斥③
    • 1.4 Linux锁的介绍与使用
      • 1.4.1 锁的类型
        • 1.4.1.1 自旋锁
        • 1.4.1.2 睡眠锁
      • 1.4.2 锁的内核函数
        • 1.4.2.1 自旋锁
        • 1.4.2.2 信号量
        • 1.4.2.3 互斥量
        • 1.4.2.4 semaphore和 mutex的区别
      • 1.4.3 何时用何种锁
      • 1.4.4 内核抢占(preempt)等额外的概念
      • 1.4.5 使用场景
        • 1.4.5.1 只在用户上下文加锁
        • 1.4.5.2 在用户上下文与 Softirqs之间加锁
        • 1.4.5.3 在用户上下文与 Tasklet之间加锁
        • 1.4.5.4 在用户上下文与 Timer之间加锁
        • 1.4.5.5 在 Tasklet与 Timer之间加锁
        • 1.4.5.6 在 Softirq之间加锁
        • 1.4.5.7 硬中断上下文

第一章 同步与互斥③

在这里插入图片描述

1.4 Linux锁的介绍与使用

本节参考:
https://www.kernel.org/doc/html/latest/locking/index.html
https://mirrors.edge.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/

1.4.1 锁的类型

Linux内核提供了很多类型的锁,它们可以分为两类:
① 自旋锁(spinning lock);
② 睡眠锁(sleeping lock)。

1.4.1.1 自旋锁

简单地说就是无法获得锁时,不会休眠,会一直循环等待。有这些自旋锁:
在这里插入图片描述
自旋锁的加锁、解锁函数是:spin_lock、spin_unlock,还可以加上各种后缀,这表示在加锁或解锁的同时,还会做额外的事情:
在这里插入图片描述

1.4.1.2 睡眠锁

简单地说就是无法获得锁时,当前线程就会休眠。有这些休眠锁:
在这里插入图片描述

1.4.2 锁的内核函数

1.4.2.1 自旋锁

spinlock函数在内核文件 include\linux\spinlock.h中声明,如下表:
在这里插入图片描述

自旋锁的加锁、解锁函数是:spin_lock、spin_unlock,还可以加上各种后缀,这表示在加锁或解锁的同时,还会做额外的事情:
在这里插入图片描述

1.4.2.2 信号量

semaphore semaphore函数在内核文件 include\linux\semaphore.h中声明,如下表:
在这里插入图片描述

1.4.2.3 互斥量

mutex mutex函数在内核文件 include\linux\mutex.h中声明,如下表:
在这里插入图片描述

1.4.2.4 semaphore和 mutex的区别

semaphore中可以指定 count为任意值,比如有 10个厕所,所以 10个人都可以使用厕所。 而 mutex的值只能设置为 1或 0,只有一个厕所。
是不是把 semaphore的值设置为 1后,它就跟 mutex一样了呢?不是的。
看一下 mutex的结构体定义,如下:
在这里插入图片描述

它里面有一项成员“struct task_struct *owner”,指向某个进程。一个 mutex只能在进程上下文中使用:谁给 mutex加锁,就只能由谁来解锁。
而 semaphore并没有这些限制,它可以用来解决“读者-写者”问题:程序 A在等待数据──想获得锁,程序 B产生数据后释放锁,这会唤醒 A来读取数据。semaphore的锁定与释放,并不限定为同一个进程。
主要区别列表如下:
在这里插入图片描述

1.4.3 何时用何种锁

本节参考:https://wenku.baidu.com/view/26adb3f5f61fb7360b4c656e.html
英文原文:https://mirrors.edge.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/ 你可能看不懂下面这个表格,请学习完后面的章节再回过头来看这个表格。
在这里插入图片描述

举例简单介绍一下,上表中第一行“IRQ Handler A”和第一列“Softirq A”的交叉点是“spin_lock_irq()”,意思就是说如果“IRQ Handler A”和“Softirq A”要竞争临界资源,那么需要使用
“spin_lock_irq()”函数。为什么不能用 spin_lock而要用 spin_lock_irq?也就是为什么要把中断给关掉?假设在 Softirq A中获得了临界资源,这时发生了 IRQ A中断,IRQ Handler A去尝试获得自旋锁,这就会导致死锁:所以需要关中断。

1.4.4 内核抢占(preempt)等额外的概念

早期的的 Linux内核是“不可抢占”的,假设有 A、B两个程序在运行,当前是程序 A在运行,什么时候轮到程序 B运行呢?
① 程序 A主动放弃 CPU:
比如它调用某个系统调用、调用某个驱动,进入内核态后执行了 schedule()主动启动一次调度。
② 程序 A调用系统函数进入内核态,从内核态返回用户态的前夕:
这时内核会判断是否应该切换程序。
③ 程序 A正在用户态运行,发生了中断:
内核处理完中断,继续执行程序 A的用户态指令的前夕,它会判断是否应该切换程序。

从这个过程可知,对于“不可抢占”的内核,当程序 A运行内核态代码时进程是无法切换的(除非程序A主动放弃),比如执行某个系统调用、执行某个驱动时,进程无法切换。
这会导致 2个问题:
① 优先级反转:
一个低优先级的程序,因为它正在内核态执行某些很耗时的操作,在这一段时间内更高优先级的程序也无法运行。
② 在内核态发生的中断不会导致进程切换

为了让系统的实时性更佳,Linux内核引入了“抢占”(preempt)的功能:进程运行于内核态时,进程调度也是可以发生的。
回到上面的例子,程序 A调用某个驱动执行耗时的操作,在这一段时间内系统是可以切换去执行更高优先级的程序。
对于可抢占的内核,编写驱动程序时要时刻注意:你的驱动程序随时可能被打断、随时是可以被另一个进程来重新执行。对于可抢占的内核,在驱动程序中要考虑对临界资源加锁。

1.4.5 使用场景

本节参考:https://wenku.baidu.com/view/26adb3f5f61fb7360b4c656e.html
英文原文:https://mirrors.edge.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/

1.4.5.1 只在用户上下文加锁

假设只有程序 A、程序 B会抢占资源,这 2个程序都是可以休眠的,所以可以使用信号量,代码如下:

static DEFINE_SPINLOCK(clock_lock); // 或 struct semaphore sem;  sema_init(&sem, 1); 
if (down_interruptible(&sem))  // if (down_trylock(&sem)) 
{ /* 获得了信号量 */ 
} /* 释放信号量 */ 
up(&sem);  

对于 down_interruptible函数,如果信号量暂时无法获得,此函数会令程序进入休眠;别的程序调用up()函数释放信号量时会唤醒它。
在 down_interruptible函数休眠过程中,如果进程收到了信号,则会从 down_interruptible中返回;对应的有另一个函数 down,在它休眠过程中会忽略任何信号。
注意:“信号量”(semaphore),不是“信号”(signal)。
也可以使用 mutex,代码如下:

static DEFINE_MUTEX(mutex);  //或 static struct mutex mutex; mutex_init(&mutex); 
mutex_lock(&mutex); 
/* 临界区 */ 
mutex_unlock(&mutex); 

注意:一般来说在同一个函数里调用 mutex_lock或 mutex_unlock,不会长期持有它。这只是惯例,如果你使用 mutex来实现驱动程序只能由一个进程打开,在 drv_open中调用 mutex_lock,在 drv_close中调用 mutex_unlock,这也完全没问题。

1.4.5.2 在用户上下文与 Softirqs之间加锁

假设这么一种情况:程序 A运行到内核态时,正在访问一个临界资源;这时发生了某个硬件中断,在硬件中断处理完后会处理 Softirq,而某个 Softirq也会访问这个临界资源。
怎么办?
在程序 A访问临界资源之前,干脆禁止 Softirq好了!
可以使用 spin_lock_bh函数,它会先禁止本地 CPU的中断下半部即 Softirq,这样本地 Softirq就不会跟它竞争了;假设别的 CPU也想获得这个资源,它也会调用 spin_lock_bh禁止它自己的 Softirq。这 2个 CPU都禁止自己的 Softirq,然后竞争 spinlock,谁抢到谁就先执行。可见,在执行临界资源的过程中,本地 CPU的 Softirq、别的 CPU的 Softirq都无法来抢占当前程序的临界资源。
释放锁的函数是 spin_unlock_bh。
spin_lock_bh/spin_unlock_bh的后缀是“_bh”,表示“Bottom Halves”,中断下半部,这是软件中断的老名字。这些函数改名为 spin_lock_softirq也许更恰当,请记住:spin_lock_bh会禁止 Softirq,而不仅仅是禁止“中断下半部”(timer、tasklet里等都是 Softirq,中断下半部只是 Softirq的一种)。
示例代码如下:

static DEFINE_SPINLOCK(lock); // static spinlock_t lock; spin_lock_init(&lock); 
spin_lock_bh(&lock); 
/* 临界区 */ 
spin_unlock_bh(&lock); 
1.4.5.3 在用户上下文与 Tasklet之间加锁

Tasklet也是 Softirq的一种,所以跟前面是“在用户上下文与 Softirqs之间加锁”完全一样。

1.4.5.4 在用户上下文与 Timer之间加锁

Timer也是 Softirq的一种,所以跟前面是“在用户上下文与 Softirqs之间加锁”完全一样。

1.4.5.5 在 Tasklet与 Timer之间加锁

假设在 Tasklet中访问临界资源,另一个 CPU会不会同时运行这个 Tasklet?不会的,所以如果只是在某个 Tasklet中访问临界资源,无需上锁。
假设在 Timer中访问临界资源,另一个 CPU会不会同时运行这个 timer?不会的,所以如果只是在某个Timer中访问临界资源,无需上锁。
如果在有 2个不同的 Tasklet或 Timer都会用到一个临界资源,那么可以使用 spin_lock()、spin_unlock()来保护临界资源。不需要用 spin_lock_bh(),因为一旦当前 CPU已经处于 Tasklet或 Timer中,同一个 CPU不会同时再执行其他 Tasklet或 Timer。

1.4.5.6 在 Softirq之间加锁

这里讲的 softirq不含 tasklet、timer。
同一个 Softirq是有可能在不同 CPU上同时运行的,所以可以使用 spin_lock()、spin_unlock()来访问临界区。如果追求更高的性能,可以使用“per-CPU array”,本章不涉及。
不同的 Softirq之间,可以使用 spin_lock()、spin_unlock()来访问临界区。

总结起来,在 Softirq之间(含 timer、tasklet、相同的 Softirq、不同的 Softirq),都可以使用spin_lock()、spin_unlock()来访问临界区。
示例代码如下:

static DEFINE_SPINLOCK(lock); // static spinlock_t lock; spin_lock_init(&lock); spin_lock(&lock); 
/* 临界区 */ 
spin_unlock(&lock); 
1.4.5.7 硬中断上下文

假设一个硬件中断服务例程与一个 Softirq共享数据,需要考虑 2点:
① Softirq执行的过程中,可能会被硬件中断打断;
② 临界区可能会被另一个 CPU上的硬件中断进入。
怎么办?
在 Softirq获得锁之前,禁止当前 CPU的中断。
在硬件中断服务例程中不需要使用 spin_lock_irq(),因为当它在执行的时间 Softirq是不可能执行的;它可以使用 spin_lock()用来防止别的 CPU抢占。
如果硬件中断 A、硬件中断 B都要访问临界资源,怎么办?这篇文章里说要使用 spin_lock_irq(): https://mirrors.edge.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/
但是我认为使用 spin_lock()就足够了。因为 Linux不支持中断嵌套,即当前 CPU正在处理中断 A时,中断 B不可能在当前 CPU上被处理,不需要再次去禁止中断;当前 CPU正在处理中断 A时,假如有另一个CPU正在处理中断 B,它们使用 spin_lock()实现互斥访问临界资源就可以了。
spin_lock_irq()/spin_unlock_irq()会禁止 /使能中断,另一套函数是spin_lock_irqsave()/spin_unlock_irqrestore(),spin_lock_irqsave()会先保存当前中断状态(使能还是禁止),再禁止中断;spin_unlock_irqrestore()会恢复之前的中断状态(不一定是使能中断,而是恢复成之前的状态)。
示例代码如下:

static DEFINE_SPINLOCK(lock); // static spinlock_t lock; spin_lock_init(&lock); spin_lock_irq(&lock); 
/* 临界区 */ 
spin_unlock_irq(&lock); 
示例代码如下: 
unsigned long flags; 
static DEFINE_SPINLOCK(lock); // static spinlock_t lock; spin_lock_init(&lock); spin_lock_irqsave(&lock, flags); 
/* 临界区 */ 
spin_unlock_irqrestore(&lock, flags); 

写在最后:这个链接是一篇很好的文档,以后我们会完全翻译出来,现在讲的知识暂时够用了。 https://mirrors.edge.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/

相关文章:

嵌入式Linux应用开发-驱动大全-第一章同步与互斥③

嵌入式Linux应用开发-驱动大全-第一章同步与互斥③ 第一章 同步与互斥③1.4 Linux锁的介绍与使用1.4.1 锁的类型1.4.1.1 自旋锁1.4.1.2 睡眠锁 1.4.2 锁的内核函数1.4.2.1 自旋锁1.4.2.2 信号量1.4.2.3 互斥量1.4.2.4 semaphore和 mutex的区别 1.4.3 何时用何种锁1.4.4 内核抢占…...

树的存储结构以及树,二叉树,森林之间的转换

目录 1.双亲表示法 2.孩子链表 3.孩子兄弟表示法 4.树与二叉树的转换 (1)树转换为二叉树 (2)二叉树转换成树 5.二叉树与森林的转化 (1)森林转换为二叉树 以下树为例 1.双亲表示法 双亲表示法定义了…...

【AI视野·今日NLP 自然语言处理论文速览 第四十二期】Wed, 27 Sep 2023

AI视野今日CS.NLP 自然语言处理论文速览 Wed, 27 Sep 2023 Totally 50 papers 👉上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Attention Satisfies: A Constraint-Satisfaction Lens on Factual Errors of Language Models Authors Mert …...

华为云云耀云服务器L实例评测|部署个人在线电子书库 calibre

华为云云耀云服务器L实例评测|部署个人在线电子书库 calibre 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 应用场景1.3 支持镜像 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 calibre3.1 calibre 介绍3.2 Docker 环境搭建3.3 c…...

代码随想录刷题 Day28

216.组合总和III 和前一个题一样,照着自己就能写出来,就多了一个判断结果是不是等于n的逻辑。有两个地方可以剪纸,一个是当和已经大于要找的时候直接返回,另一个是当剩余元素少于三个的时候直接返回(第一层递归是少于…...

【生命周期】

生命周期 1 引出生命周期2 分析生命周期3 总结生命周期 1 引出生命周期 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta …...

【C语言 模拟实现memcpy函数、memcpy函数】

C语言程序设计笔记---027 C语言之模拟实现memcpy函数、memcpy函数1、介绍memcpy函数1.1、模拟实现memcpy函数 2、介绍memmove函数2.1、模拟实现memmove函数 3、结语 C语言之模拟实现memcpy函数、memcpy函数 前言&#xff1a; 通过C语言内存函数的知识&#xff0c;这篇将对memc…...

opencv视频文件的读取,处理与保存

文章目录 opencv视频文件的读取&#xff0c;处理与保存一、视频文件的读取&#xff1a;1、cv::VideoCapture是OpenCV库中用于处理视频输入的类&#xff0c;它提供了一种简单的方法来从摄像头&#xff0c;视频文件、或图像序列中读取帧&#xff1b;&#xff08;1&#xff09;打开…...

java - 七大比较排序 - 详解

前言 本篇介绍了七大比较排序&#xff0c;直接插入排序&#xff0c;希尔排序&#xff0c;冒泡排序&#xff0c;堆排序&#xff0c;选择排序&#xff0c;快速排序&#xff0c;归并排序&#xff0c;一些简单思想代码实现&#xff0c;如有错误&#xff0c;请在评论区指正&#xf…...

项目集成七牛云存储sdk

以PHP为例 第一步&#xff1a;下载sdk PHP SDK_SDK 下载_对象存储 - 七牛开发者中心 sdk下载成功之后&#xff0c;将sdk放入项目中&#xff0c;目录选择以自己项目实际情况而定。 注意&#xff1a;在examples目录中有各种上传文件的参考示例&#xff0c;这里我们主要参考的是…...

docker-compose一键启动neo4j

下载镜像 docker pull neo4j:3.5.22-community 编写配置文件 参考文档 编写docker-compose.yml文件 version: "3"services:neo4j:image: neo4j:3.5.22-communitycontainer_name: neo4j restart: alwaysports:- 7474:7474- 7687:7687environment:- NEO4J_AUTH:ne…...

深入剖析@ConfigurationProperties注解

当我们构建Spring Boot应用程序时&#xff0c;配置属性通常是不可或缺的一部分。Spring Boot提供了多种方式来管理这些属性&#xff0c;其中之一是使用ConfigurationProperties注解。这篇博客将详细解释ConfigurationProperties注解以及如何使用它来管理和映射配置属性。 什么…...

北京开发APP需要多少钱

北京开发一个移动应用&#xff08;APP&#xff09;的费用因多种因素而异&#xff0c;包括项目的规模、复杂性、所需功能、设计要求、技术选择、开发团队的经验和地理位置等。一般来说&#xff0c;北京的APP开发费用通常较高&#xff0c;因为这是中国的主要技术和创新中心之一&a…...

self-attention、transformer、bert理解

参考李宏毅老师的视频 https://www.bilibili.com/video/BV1LP411b7zS?p2&spm_id_frompageDriver&vd_sourcec67a2725ac3ca01c38eb3916d221e708 一个输入&#xff0c;一个输出&#xff0c;未考虑输入之间的关系&#xff01;&#xff01;&#xff01; self-attention…...

junit @ExcludePackages排除多个包

在JUnit中&#xff0c;可以使用ExcludePackages注解来排除多个包。该注解可以用在测试类或测试方法上。 如果要排除多个包&#xff0c;可以在ExcludePackages注解的value属性中使用数组来指定要排除的包名。例如&#xff0c;要排除包com.example.package1和com.example.packag…...

Explain执行计划字段解释说明---select_type、table、patitions字段说明

1、select_type的类型有哪些 2、select_type的查询类型说明 1、SIMPLE 简单的 select 查询,查询中不包含子查询或者UNION 2、PRIMARY 查询中若包含任何复杂的子部分&#xff0c;最外层查询则被标记为Primary 3、DERIVED 在FROM列表中包含的子查询被标记为DERIVED(衍生)&…...

云原生微服务 第六章 Spring Cloud Netflix Eureka集成远程调用、负载均衡组件OpenFeign

系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 文章目录 系列文章目录前言1、OpenFeign的实现…...

四、2023.9.30.C++面向对象end.4

文章目录 49、 简述一下什么是常函数&#xff0c;有什么作用&#xff1f;50、 说说什么是虚继承&#xff0c;解决什么问题&#xff0c;如何实现&#xff1f;51、简述一下虚函数和纯虚函数&#xff0c;以及实现原理&#xff1f;52、说说纯虚函数能实例化吗&#xff0c;为什么&am…...

【Java】包

package 包&#xff08;package&#xff09;:其实就是文件夹。 作用&#xff1a;对类进行分类管理。 包的定义格式 格式&#xff1a;package 包名&#xff08;多级包用 . 分开&#xff09; 范例&#xff1a;package com.mayikt.demo01 带包的Java类编译和执行 1. 手动建包 安装…...

Hive【Hive(二)DML】

启动 hive 命令行&#xff1a; hive DML 数据操作 1、数据导入 1.1、向表中装载数据&#xff08;load&#xff09; 语法&#xff1a; hive> load data [local] inpath 数据的path [overwrite] into table student [partition (partcol1val1,…)];&#xff08;1&#x…...

Smart_rtmpd配置全解:从单局域网到跨网段,你的OBS推流服务器搭建指南

Smart_rtmpd高阶配置指南&#xff1a;从局域网到跨网段的OBS推流实战 在当前的数字内容创作浪潮中&#xff0c;实时视频流传输已成为游戏直播、在线教育、企业内训等场景的刚需。对于技术爱好者和小型团队而言&#xff0c;自建推流服务器不仅能避免第三方平台的限制&#xff0c…...

Arm编译器浮点运算实现与优化实践

1. Arm编译器中的浮点运算实现机制在嵌入式开发领域&#xff0c;浮点运算的实现质量直接影响着数值计算的精度和系统性能。Arm编译器通过深度整合IEEE 754标准&#xff0c;为开发者提供了可靠的浮点运算支持。让我们先看一个典型场景&#xff1a;当使用printf输出浮点数时&…...

泄爆门是什么材质 工业厂房专用防爆门详解

很多工地、厂房分不清泄爆门和普通防爆门&#xff0c;关键差别就在材质和结构。本文详细讲解泄爆门常用材质、每种材质优缺点、适用场景&#xff0c;以及工业厂房专用防爆门选型要点、验收标准&#xff0c;做工程、采购、消防整改都能直接参考。在化工厂、粉尘车间、锅炉房、饲…...

基于MCP协议连接AI与CDP:BlueConic-MCP项目实战解析

1. 项目概述&#xff1a;当营销技术遇上AI代理最近在折腾AI应用开发&#xff0c;特别是围绕OpenAI的Assistant API和各类AI Agent框架时&#xff0c;有一个痛点越来越明显&#xff1a;这些智能体能力再强&#xff0c;如果它们对业务的核心数据一无所知&#xff0c;那也只是一个…...

手把手教你:没有ST-LINK,如何用USB给STM32烧录程序(DFU模式保姆级教程)

零成本玩转STM32&#xff1a;USB-DFU模式烧录全攻略 当你深夜调试STM32项目时&#xff0c;突然发现手边没有ST-LINK&#xff0c;而快递至少要等三天——这种场景我经历过太多次。直到发现DFU模式这个隐藏技能&#xff0c;所有问题迎刃而解。本文将分享如何仅用一根USB线完成固件…...

OpenClaw Deck:为Steam Deck打造开源模块化工具集

1. 项目概述&#xff1a;一个为Steam Deck量身定制的开源工具集如果你是一位Steam Deck的深度用户&#xff0c;大概率经历过这样的场景&#xff1a;想在掌机上玩一些非Steam平台的游戏&#xff0c;或者想对系统进行一些深度定制&#xff0c;却发现官方系统虽然稳定&#xff0c;…...

应对2026检测算法:论文AI率居高不下怎么救?5款降AI工具深度实测

最近不少学弟学妹在后台跟我倒苦水&#xff0c;说查重率好不容易低了&#xff0c;结果AI率越改越高。眼看临近DDL&#xff0c;生怕又因为这个耽误答辩。 作为已经摸爬滚打出来的老学长&#xff0c;今天我就根据我总结出来的经验&#xff0c;从检测系统的底层逻辑开始讲起&…...

Herc.ai:一站式AI API网关,统一调用GPT-4、Gemini等主流模型

1. 项目概述&#xff1a;Herc.ai&#xff0c;一个面向开发者的全能AI API网关如果你正在寻找一个能让你在项目中轻松集成GPT-4、Gemini、DALL-E、Flux等主流AI模型&#xff0c;同时又不想被单一供应商绑定、不想处理复杂的多API密钥管理、并且希望有一个统一的、开发者友好的接…...

大模型学习指南:小白也能轻松掌握AI,提升效率与收入(收藏版)

本文针对想学习大模型的普通用户&#xff0c;破除学习AI的常见误区&#xff0c;提供实用学习路径。文章强调从实际应用场景出发&#xff0c;而非深入技术原理&#xff0c;介绍了如何利用AI提升办公效率、进行内容创作、结合本职工作以及构建个人智能体助手。此外&#xff0c;文…...

为什么92%的数据分析师还没用上Gemini Sheets功能?—— 一份被谷歌官方忽略的AI分析落地清单

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Gemini Sheets数据分析的现状与认知断层 Gemini Sheets 作为 Google Workspace 生态中新兴的 AI 增强型电子表格工具&#xff0c;正逐步替代传统 Sheets 的部分分析场景。然而&#xff0c;当前用户实践…...