Spark SQL进阶:解锁大数据处理的新姿势

目录

一、Spark SQL,为何进阶?

二、进阶特性深剖析

2.1 窗口函数:数据洞察的新视角

2.2 高级聚合:挖掘数据深度价值

2.3 自定义函数(UDF 和 UDTF):拓展功能边界

三、性能优化实战

3.1 数据分区与缓存策略

3.2 解决数据倾斜问题

3.3 合理配置 Spark 参数

四、实际项目案例

4.1 项目背景与数据介绍

4.2 Spark SQL 进阶应用

4.3 优化过程与效果展示

五、总结与展望


一、Spark SQL,为何进阶?

在大数据的广袤领域中,数据量正以惊人的速度增长,处理需求也变得日益复杂。想象一下,一家超大型电商企业,每天要处理数以亿计的订单数据、用户浏览记录以及商品信息。这些数据不仅规模庞大,而且结构复杂,有结构化的订单表格数据,也有非结构化的用户评价文本。企业需要从这些数据中快速分析出销售趋势、用户偏好,以便及时调整营销策略和商品库存。

在这样的大数据处理场景下,基础的 Spark SQL 功能渐渐有些力不从心。从性能层面来看,当数据量达到 PB 级,简单的查询操作也可能变得异常缓慢。比如对全量用户数据进行多表关联查询,基础的 Spark SQL 配置可能会因为内存不足或资源分配不合理,导致任务长时间运行甚至失败。而且在面对复杂查询时,像涉及多层嵌套子查询、窗口函数与复杂聚合函数组合使用的场景,基础功能很难高效地生成最优执行计划。这就好比驾驶一辆普通轿车在崎岖的山路上行驶,动力和操控都难以满足需求,所以进阶学习 Spark SQL 迫在眉睫。

二、进阶特性深剖析

2.1 窗口函数:数据洞察的新视角

窗口函数,在 Spark SQL 中是一个强大的工具,它为数据分析提供了全新的视角。与普通聚合函数不同,窗口函数可以在不改变数据行数的前提下,对数据进行基于“窗口”的计算。简单来说,窗口就是一个数据的子集,这个子集可以是按照某一列进行分区后的一组数据,也可以是按照一定顺序排列的连续数据行。

以电商领域中计算用户在一段时间内的累计消费金额为例。假设有一个包含用户 ID、消费日期和消费金额的订单表,使用窗口函数,我们可以轻松地计算出每个用户在每天的累计消费金额。在 Spark SQL 中,实现代码如下:

SELECTuser_id,order_date,amount,SUM(amount) OVER (PARTITION BY user_id ORDER BY order_date) AS cumulative_amount
FROMorders;

在这段代码中,SUM(amount) OVER (PARTITION BY user_id ORDER BY order_date) 就是窗口函数的应用。PARTITION BY user_id 表示按照用户 ID 进行分区,每个用户的数据会被划分到不同的窗口中;ORDER BY order_date 则是在每个分区内按照消费日期进行排序。这样,SUM(amount) 就会在每个用户的分区内,按照日期顺序累计计算消费金额。窗口函数的优势在于,它能在保留原始数据行的基础上,进行复杂的计算,比如计算移动平均值、排名等,这为深入的数据洞察提供了便利。

2.2 高级聚合:挖掘数据深度价值

在数据分析中,普通的聚合函数,如 SUM、AVG、COUNT 等,虽然能满足一些基本的统计需求,但在面对复杂的多维数据分析时,往往显得力不从心。比如,当我们想要从多个维度对数据进行聚合分析时,普通聚合函数就需要编写大量的重复代码,而且效率较低。

这时,GROUPING SETS、CUBE、ROLLUP 等高级聚合操作就派上了用场。GROUPING SETS 允许我们在一次查询中指定多个聚合维度。比如在电商数据分析中,我们既想按商品类别统计销售额,又想按销售地区统计销售额,使用 GROUPING SETS 可以这样实现:

SELECTproduct_category,sales_region,SUM(sales_amount) AS total_sales
FROMsales_data
GROUP BYGROUPING SETS ((product_category), (sales_region));

CUBE 操作则更为强大,它会生成所有可能的维度组合的聚合结果。例如:

SELECTproduct_category,sales_region,SUM(sales_amount) AS total_sales
FROMsales_data
GROUP BYCUBE (product_category, sales_region);

这会得到按商品类别和销售地区的所有组合的销售额统计,包括按商品类别汇总、按销售地区汇总以及两者交叉汇总。ROLLUP 操作类似于 CUBE,但它是按照指定维度的层次结构进行聚合,生成的结果是一种更有层次的汇总数据。通过这些高级聚合操作,我们可以在一次查询中获取丰富的多维数据分析结果,大大提高了数据分析的效率和深度。

2.3 自定义函数(UDF 和 UDTF):拓展功能边界

在 Spark SQL 中,虽然内置了丰富的函数,但在实际应用中,我们常常会遇到一些特殊的业务逻辑,需要自定义函数来实现。自定义函数主要包括 UDF(User-Defined Function)和 UDTF(User-Defined Table-Generating Function)。

UDF 用于对单行数据进行处理,并返回一个标量值。比如,我们有一个需求,要将用户输入的字符串转换为特定格式,如将“hello world”转换为“Hello World”(首字母大写),就可以通过自定义 UDF 来实现。在 Scala 中,实现代码如下:

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions.udfval spark = SparkSession.builder.appName("UDFExample").master("local").getOrCreate()
val capitalizeUDF = udf((input: String) => input.capitalize)
val data = Seq(("hello world"), ("scala is awesome"))
val df = spark.createDataFrame(data).toDF("input_string")
df.select(capitalizeUDF($"input_string").alias("capitalized_string")).show()

UDTF 则用于将一行数据转换为多行数据。例如,我们有一个字段存储了用户的多个爱好,以逗号分隔,如 “reading,writing,swimming”,现在需要将每个爱好拆分成单独的行,就可以使用 UDTF。在 Spark SQL 中,可以通过 explode 函数结合自定义逻辑来实现类似 UDTF 的功能:

import org.apache.spark.sql.functions.explodeval hobbiesData = Seq(("Alice", "reading,writing,swimming"))
val hobbiesDF = spark.createDataFrame(hobbiesData).toDF("user", "hobbies")
hobbiesDF.select($"user", explode(split($"hobbies", ",")).alias("hobby")).show()

UDF 和 UDTF 极大地拓展了 Spark SQL 的功能边界,使我们能够根据具体的业务需求,灵活地进行数据处理和分析。

三、性能优化实战

3.1 数据分区与缓存策略

在大数据处理中,数据分区是提升 Spark SQL 性能的关键手段。简单来说,数据分区就是将大规模的数据集合按照特定的规则划分成多个小的子集,每个子集就是一个分区。这样做的好处在于,当进行数据处理时,不同的分区可以并行处理,大大提高了处理效率。例如,在处理一个包含海量用户行为数据的表时,我们可以根据时间(如按天、按月)或用户 ID 的哈希值等作为分区键。如果按时间分区,查询某一天的用户行为数据时,就可以直接定位到对应的分区,而无需扫描整个数据集,极大地减少了数据读取量和处理时间。

缓存策略在 Spark SQL 中也起着举足轻重的作用。对于那些经常被查询的数据,将其缓存到内存中,可以避免重复读取磁盘,从而显著提高查询速度。比如,在一个电商数据分析系统中,商品的基本信息表(如商品名称、价格、库存等)是经常被查询的。我们可以使用以下代码将该表缓存起来:

val productInfoDF = spark.sql("SELECT * FROM product_info")
productInfoDF.cache()

这样,后续对 productInfoDF 的查询就可以直接从内存中获取数据,大大缩短了查询响应时间。需要注意的是,缓存数据会占用内存资源,所以要根据集群的内存情况和数据的使用频率,合理选择需要缓存的数据。

3.2 解决数据倾斜问题

数据倾斜是在 Spark SQL 处理过程中经常遇到的一个棘手问题。它指的是在数据分布上存在严重的不均衡,导致某些任务处理的数据量远远超过其他任务。这种情况会使得整个作业的执行效率大幅下降,因为整个作业的完成时间取决于处理数据量最大的那个任务。例如,在分析电商订单数据时,假设要按地区统计订单数量,如果某个地区的订单量特别大,而其他地区订单量相对较少,就会发生数据倾斜。

数据倾斜的产生原因主要是数据本身的分布特性以及所使用的操作。以电商订单按地区分析为例,可能由于某个地区举办了大型促销活动,导致该地区订单量暴增。在进行数据聚合或连接操作时,大量相同地区的数据会被分配到同一个任务中处理,从而引发数据倾斜。

针对数据倾斜问题,有多种解决方法。一种常见的方法是扩大 shuffle 分区数,通过增加分区数量,将原本集中在少数分区的数据分散到更多的分区中,从而减轻单个任务的负担。例如,可以在 Spark 配置中设置 spark.sql.shuffle.partitions 参数来增加分区数:

spark.conf.set("spark.sql.shuffle.partitions", "400")

另一种方法是使用随机前缀。对于那些数据量特别大的键值对,在进行 shuffle 操作前,给它们的键添加一个随机前缀,使它们分散到不同的分区中。比如,对于订单量特别大的地区,在处理前给该地区的订单数据的键添加随机数字前缀,这样原本集中的键就会分散到多个分区,避免了数据过度集中在少数任务中。

3.3 合理配置 Spark 参数

在 Spark SQL 中,合理配置参数是优化性能的重要环节。spark.sql.shuffle.partitions 参数决定了 shuffle 操作时的分区数量,如前文所述,适当增加该参数的值可以缓解数据倾斜问题,但如果设置过大,也会增加任务调度和管理的开销。一般来说,需要根据数据量、集群节点数量和每个节点的资源情况来综合调整。例如,在一个拥有 10 个节点,每个节点内存为 32GB,数据量为 1TB 的集群中处理数据时,可以先尝试将 spark.sql.shuffle.partitions 设置为 200,然后根据作业执行情况和性能指标(如执行时间、资源利用率等)进行微调。

spark.sql.broadcastTimeout 参数设置了广播变量的超时时间。在进行表连接操作时,如果一个表的数据量较小,Spark 会自动将其广播到各个节点,以避免数据在节点间传输。但如果广播过程中出现网络延迟等问题,可能会导致广播超时。通过合理设置这个参数,可以确保广播操作能够顺利完成。比如,在网络状况较好的集群中,可以将该参数设置为较短的时间(如 60 秒);而在网络不稳定的环境中,则需要适当延长超时时间(如 120 秒)。

此外,还有 spark.sql.inMemoryColumnarStorage.compressed 参数,用于控制是否对内存中的列存储数据进行压缩。开启压缩可以减少内存占用,但会增加一定的压缩和解压缩开销。对于内存资源紧张的集群,开启该参数可能会显著提高内存利用率,从而提升整体性能。例如,在处理包含大量文本数据的表时,开启压缩可以有效减少内存使用,同时由于文本数据的压缩率通常较高,压缩和解压缩的性能开销相对较小,整体上能够提升作业的执行效率。

四、实际项目案例

4.1 项目背景与数据介绍

在电商行业蓬勃发展的当下,数据驱动决策成为企业发展的关键。本次分析聚焦于某电商平台,随着业务的快速扩张,平台积累了海量的数据。企业希望通过对这些数据的深入分析,挖掘用户行为模式、销售趋势等有价值的信息,从而优化营销策略、提升用户体验并增加销售额。

项目中涉及的数据主要包括用户信息、订单数据和商品数据。用户信息表包含用户 ID、注册时间、性别、年龄、地域等字段,数据规模达到千万级别,这些数据为分析用户特征和行为提供了基础。订单数据表记录了每一笔订单的详细信息,如订单 ID、用户 ID、商品 ID、订单金额、下单时间、支付方式等,每天新增数据量约百万条。商品数据表则涵盖了商品 ID、商品名称、类别、价格、库存等信息,商品种类丰富,数据量也在不断增长。这些数据具有数据量大、实时性要求高、数据关系复杂等特点,需要高效的处理和分析技术。

4.2 Spark SQL 进阶应用

在分析用户购买行为时,窗口函数发挥了重要作用。我们使用窗口函数计算用户的购买频率,找出购买频率高的用户。例如,通过以下 SQL 语句可以计算每个用户在一个月内的购买次数,并按照购买次数进行排名:

SELECTuser_id,COUNT(*) OVER (PARTITION BY user_id ORDER BY order_time ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS purchase_count,RANK() OVER (ORDER BY COUNT(*) OVER (PARTITION BY user_id ORDER BY order_time ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) DESC) AS purchase_rank
FROMorders
WHEREorder_time BETWEEN '2024-01-01' AND '2024-01-31';

这样,我们可以轻松识别出那些高频购买用户,为后续的精准营销提供目标用户群体。

在对订单数据进行多维分析时,高级聚合操作成为有力工具。利用 GROUPING SETS,我们可以同时按地区和时间段统计销售额。示例代码如下:

SELECTsales_region,order_date,SUM(order_amount) AS total_sales
FROMorders
GROUP BYGROUPING SETS ((sales_region), (order_date), (sales_region, order_date));

这使得我们能够从多个维度全面了解销售情况,发现不同地区和时间段的销售差异,为制定销售策略提供数据支持。

对于商品描述等文本数据,我们编写了 UDF 来进行处理。比如,需要提取商品描述中的关键词,以便更好地进行商品分类和搜索。我们可以编写一个 UDF,使用自然语言处理库(如 NLTK 或 SnowNLP)来实现关键词提取。在 Scala 中,实现代码如下:

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions.udf
import org.snu.ids.ha.index.KeywordExtractorval spark = SparkSession.builder.appName("UDFExample").master("local").getOrCreate()
val keywordExtractor = new KeywordExtractor()
val extractKeywordsUDF = udf((description: String) => {val keywords = keywordExtractor.extractKeyword(description, true)keywords.map(_._1).mkString(",")
})val productData = Seq(("Product1", "This is a high - quality laptop with advanced features"), ("Product2", "A beautiful dress for special occasions"))
val productDF = spark.createDataFrame(productData).toDF("product_name", "description")
productDF.select($"product_name", extractKeywordsUDF($"description").alias("keywords")).show()

通过这个 UDF,我们可以从商品描述中提取出关键词,为商品的精准推荐和搜索功能提供支持。

4.3 优化过程与效果展示

在项目实施过程中,我们遇到了性能问题。随着数据量的不断增加,一些复杂查询的执行时间过长,严重影响了分析效率。例如,在进行多表关联和复杂聚合查询时,任务常常因为内存不足而失败。经过分析,我们发现主要原因是数据倾斜和资源分配不合理。

针对这些问题,我们采取了一系列优化措施。在数据分区方面,对订单表按照订单时间进行分区,这样在查询特定时间段的订单数据时,可以大大减少数据扫描范围。对于经常被查询的数据,如商品信息表,我们进行了缓存处理,将其缓存在内存中,提高查询速度。同时,我们还调整了 Spark 的相关参数,如增加 spark.sql.shuffle.partitions 的值,从默认的 200 增加到 400,以缓解数据倾斜问题;合理设置 spark.executor.memory 和 spark.executor.cores,根据集群节点的配置,将每个 Executor 的内存设置为 8GB,核心数设置为 4。

优化前后的性能对比十分显著。优化前,一个复杂的多维分析查询可能需要运行数小时,而优化后,执行时间缩短到了几十分钟,效率提升了数倍。内存使用率也得到了有效控制,任务失败率大幅降低,从原来的 10% 降低到了 1% 以内,大大提高了数据分析的效率和稳定性,为企业的决策提供了更及时、准确的数据支持。

五、总结与展望

在大数据处理的征程中,Spark SQL 进阶之路充满了探索与挑战,也收获了强大的能力与显著的成果。从窗口函数提供的独特数据洞察视角,到高级聚合操作挖掘出的数据深度价值,再到自定义函数拓展的功能边界,每一个进阶特性都为我们处理复杂数据提供了有力武器。在性能优化实战中,通过合理运用数据分区与缓存策略、解决数据倾斜问题以及精准配置 Spark 参数,我们能够让 Spark SQL 在面对海量数据时依然保持高效运行。

实际项目案例也充分证明了 Spark SQL 进阶技术的价值。在电商数据分析等复杂场景中,通过运用这些进阶技术,企业能够从海量数据中快速提取有价值的信息,为决策提供精准的数据支持,从而在激烈的市场竞争中占据优势。

展望未来,随着大数据技术的不断发展,Spark SQL 也将持续演进。数据湖与数据仓库的融合趋势将使 Spark SQL 在处理不同类型数据时更加灵活高效;在人工智能与大数据深度融合的背景下,Spark SQL 有望与机器学习、深度学习算法更紧密结合,实现更智能化的数据处理和分析。对于广大数据从业者而言,持续学习和探索 Spark SQL 的进阶技术,不仅能够提升自身在大数据领域的竞争力,还能为推动大数据技术的发展贡献力量。让我们在 Spark SQL 的进阶道路上不断前行,挖掘更多数据价值,迎接大数据时代的更多挑战与机遇。

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

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

相关文章

如何利用 Conda 安装 Pytorch 教程 ?

如何利用 Conda 安装 Pytorch 教程 ? 总共分为六步走: (1)第一步:验证conda 环境是否安装好? 1) conda -V2) conda --version(2)第二步:查看现有环境 conda env list…

什么是HTTP

HTTP(HyperText Transfer Protocol)是万维网数据通信的基础协议,作为应用层协议具有以下关键特性: 客户端-服务器模型:基于请求/响应模式 无状态协议:默认不保留通信状态 可扩展性:通过首部字…

2025-05-27 学习记录--Python-模块

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。💪🏻 一、模块 ⭐️ (一)模块的导入与使用 🍭 模块的导入:🐝 模块 就好比…

leetcode 131. Palindrome Partitioning

目录 一、题目描述 二、方法1、回溯法每次暴力判断回文子串 三、方法2、动态规划回溯法 一、题目描述 分割回文子串 131. Palindrome Partitioning 二、方法1、回溯法每次暴力判断回文子串 class Solution {vector<vector<string>> res;vector<string>…

重构开发范式!飞算JavaAI革新Spring Cloud分布式系统开发

分布式系统凭借高可用性、可扩展性等核心优势&#xff0c;成为大型软件项目的标配架构。Spring Cloud作为Java生态最主流的分布式开发框架&#xff0c;虽被广泛应用于微服务架构搭建&#xff0c;但其传统开发模式却面临效率瓶颈——从服务注册中心配置到网关路由规则编写&#…

python 生成复杂表格,自动分页等功能

py&#xff54;&#xff48;&#xff4f;&#xff4e; 生成复杂表格&#xff0c;自动分页等功能 解决将Python中的树形目录数据转换为Word表格&#xff0c;并生成带有合并单元格的检测报告的问题。首先&#xff0c;要解决“tree目录数据”和“Word表格互换”&#xff0c;指将树…

根据Cortex-M3(包括STM32F1)权威指南讲解MCU内存架构与如何查看编译器生成的地址具体位置

首先我们先查看官方对于Cortex-M3预定义的存储器映射 1.存储器映射 1.1 Cortex-M3架构的存储器结构 内部私有外设总线&#xff1a;即AHB总线&#xff0c;包括NVIC中断&#xff0c;ITM硬件调试&#xff0c;FPB, DWT。 外部私有外设总线&#xff1a;即APB总线&#xff0c;用于…

Linux中硬件信息查询利器——lshw命令详解!

lshw&#xff08;List Hardware&#xff09;是 Linux 系统下的一款命令行工具&#xff0c;用于全面检测并显示详细的硬件信息。它能够报告 CPU、内存、主板、存储设备、显卡、网络设备等几乎所有硬件组件的详细信息&#xff0c;适用于系统管理、故障排查和硬件兼容性检查等场景…

用llama3微调了一个WiFiGPT 用于室内定位

一段话总结 本文提出WiFiGPT,一种基于Decoder-Only Transformer(如LLaMA 3)的室内定位系统,通过将WiFi遥测数据(如CSI、FTM、RSSI)转换为文本序列进行端到端训练,无需手工特征工程即可实现高精度定位。实验表明,WiFiGPT在LOS环境中实现亚米级精度(MAE低至0.90米),在…

大模型系列22-MCP

大模型系列22-MCP 玩转 MCP 协议&#xff1a;用 Cline DeepSeek 接入天气服务什么是 MCP&#xff1f;环境准备&#xff1a;VScode Cline DeepSeek**配置 DeepSeek 模型&#xff1a;****配置 MCP 工具****uvx是什么&#xff1f;****安装 uv&#xff08;会自动有 uvx 命令&…

Go语言Map的底层原理

概念 map 又称字典&#xff0c;是一种常用的数据结构&#xff0c;核心特征包含下述三点&#xff1a; &#xff08;1&#xff09;存储基于 key-value 对映射的模式&#xff1b; &#xff08;2&#xff09;基于 key 维度实现存储数据的去重&#xff1b; &#xff08;3&#x…

循环神经网络(RNN):原理、架构与实战

循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一类专门处理序列数据的神经网络&#xff0c;如时间序列、自然语言、音频等。与前馈神经网络不同&#xff0c;RNN 引入了循环结构&#xff0c;能够捕捉序列中的时序信息&#xff0c;使模型在不同时间步之间…

java 项目登录请求业务解耦模块全面

登录是统一的闸机&#xff1b; 密码存在数据库中&#xff0c;用的是密文&#xff0c;后端加密&#xff0c;和数据库中做对比 1、UserController public class UserController{Autowiredprivate IuserService userservicepublic JsonResult login(Validated RequestBody UserLo…

【手写数据库核心揭秘系列】第9节 可重入的SQL解析器,不断解析Structure Query Language,语言翻译好帮手

可重入的SQL解析器 文章目录 可重入的SQL解析器一、概述 二、可重入解析器 2.1 可重入设置 2.2 记录状态的数据结构 2.3 节点数据类型定义 2.4 头文件引用 三、调整后的程序结构 四、总结 一、概述 现在就来修改之前sqlscanner.l和sqlgram.y程序,可以不断输入SQL语句,循环执…

微软开源bitnet b1.58大模型,应用效果测评(问答、知识、数学、逻辑、分析)

微软开源bitnet b1.58大模型,应用效果测评(问答、知识、数学、逻辑、分析) 目 录 1. 前言... 2 2. 应用部署... 2 3. 应用效果... 3 1.1 问答方面... 3 1.2 知识方面... 4 1.3 数字运算... 6 1.4 逻辑方面... …

用HTML5+JavaScript实现汉字转拼音工具

用HTML5JavaScript实现汉字转拼音工具 前一篇博文&#xff08;https://blog.csdn.net/cnds123/article/details/148067680&#xff09;提到&#xff0c;当需要将拼音添加到汉字上面时&#xff0c;用python实现比HTML5JavaScript实现繁琐。在这篇博文中用HTML5JavaScript实现汉…

鸿蒙OSUniApp 开发的动态背景动画组件#三方框架 #Uniapp

使用 UniApp 开发的动态背景动画组件 前言 在移动应用开发中&#xff0c;动态背景动画不仅能提升界面美感&#xff0c;还能增强用户的沉浸感和品牌辨识度。无论是登录页、首页还是活动页&#xff0c;恰到好处的动态背景都能让产品脱颖而出。随着鸿蒙&#xff08;HarmonyOS&am…

云原生技术架构技术探索

文章目录 前言一、什么是云原生技术架构二、云原生技术架构的优势三、云原生技术架构的应用场景结语 前言 在当今的技术领域&#xff0c;云原生技术架构正以一种势不可挡的姿态席卷而来&#xff0c;成为了众多开发者、企业和技术爱好者关注的焦点。那么&#xff0c;究竟什么是…

AWS之AI服务

目录 一、AWS AI布局 ​​1. 底层基础设施与芯片​​ ​​2. AI训练框架与平台​​ ​​3. 大模型与应用层​​ ​​4. 超级计算与网络​​ ​​与竞品对比​​ AI服务 ​​1. 机器学习平台​​ ​​2. 预训练AI服务​​ ​​3. 边缘与物联网AI​​ ​​4. 数据与AI…

lwip_bind、lwip_listen 是阻塞函数吗

在 lwIP 协议栈中&#xff0c;lwip_bind 和 lwip_listen 函数本质上是非阻塞的。 通常&#xff0c;bind和listen在大多数实现中都是非阻塞的&#xff0c;因为它们只是设置套接字的属性&#xff0c;不需要等待外部事件。阻塞通常发生在接受连接&#xff08;accept&#xff09;、…