拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Gradle Core Execution 平台深度解析:执行引擎、快照/指纹与工作验证

构建工具开发工具【免费下载链接】gradleAdaptable, fast automation for all项目地址https://gitcode.com/gh_mirrors/gr/gradle点击查看免费下载本篇技术指南围绕 Gradle 源码仓库中的执行平台核心文档platforms/core-execution/README.md展开系统讲解 Gradle 用于在构建上下文中执行工作work的基础设施执行引擎Execution Engine、快照与指纹Snapshotting Fingerprinting以及工作验证Work Validation。读者读完本文后将理解 Gradle 的任务Task、构件变换Artifact Transform乃至构建脚本编译、访问器生成等内部工作是如何被统一、安全、高效地执行并掌握 up-to-date 检查、构建缓存、增量执行、输入规范化等核心机制的底层原理可直接对照源码继续深挖。一、执行平台总览三份文档构成的核心骨架Gradle 仓库将在构建上下文中执行工作的基础设施集中放在platforms/core-execution目录下其顶层 README 以一份**术语表Glossary**的形式给出了整个执行平台的核心定义并链接到三份详细指南指南相对仓库根的路径主题Execution Engine执行引擎platforms/core-execution/execution/README.md执行平台的主组件如何声明并安全高效地执行工作单元Snapshotting and Fingerprinting快照与指纹platforms/core-execution/snapshots/README.md如何捕获输入/输出的原始状态与规范化状态Work Validation工作验证platforms/core-execution/Work Validation.md如何检查工作单元及其属性是否被正确定义与接线[!NOTE] 顶层 README 明确说明执行引擎是 Gradle 中执行工作的主要方式同时其部分部件也被用于 Develocity 的 Maven 与 sbt 扩展中执行引擎通过跟踪不同工作单元如任务与构件变换的**执行状态execution state**来优化执行并保障安全还用于高效执行构建脚本编译、访问器生成等内部工作。从目录结构看platforms/core-execution下还包含了file-watching文件系统监听、hashing/hashing-services哈希、normalization/normalization-api/normalization-java输入规范化、snapshots快照与虚拟文件系统、workers/worker-main/worker-process-services等实现子模块为上述三份文档描述的概念提供了源码级支撑。二、核心术语执行引擎、执行状态、快照与指纹2.1 执行引擎Execution Engine执行引擎用于安全且高效地物化manifest工作单元的输出。它是 Gradle 执行工作的主要方式其核心设计目标包括提供一种简单、统一的方式来声明工作单元unit of work让引擎能够在并发环境下安全高效地产出它们的输出引擎本身是完全线程安全的保证并行执行多个工作单元不会相互干扰即使多个进程同时执行工作单元也是如此引擎不负责决定哪些工作单元应当执行也不负责调度执行那是调度器 Scheduler 的职责——它只关注如何执行与如何安全复用输出。任何具有明确定义的输入与输出、且需要安全执行或输出复用的动作都可以用执行引擎实现。Gradle 的长期愿景是所有这类工作都经由执行引擎执行并且执行引擎保持与 Gradle 概念解耦——既有利于未来更广泛的使用也能保持架构清晰、API 契约简单易懂。从执行引擎的实现看其主目录 platforms/core-execution/execution/src/main/java 下有约 200 个 Java 文件其中包含下文将详细剖析的步骤管线实现如ValidateStep同时配套的 执行引擎示意图 以可缩放 SVG 的形式直观呈现了整个引擎的流水线建议用浏览器新标签页打开查看细节。Gradle 执行引擎示意图展示了 Identify、身份缓存、可变/不可变流水线、构建缓存与执行等完整步骤管线2.2 工作单元Unit of Work工作单元由以下要素定义一个可识别identifiable的动作action一组已知的输入inputs一组期望的输出outputs。其中动作是相对于其输入而言的纯函数——等效的输入产生等效的输出。输入和输出可以是标量值也可以是文件和目录当前实现仅支持文件类输出但这属于可以解除的历史限制。输入在工作开始执行后应保持不可变输出只能由执行中的动作修改。当工作产出文件时它在一个仅对该工作动作可见的工作空间workspace目录中执行以此实现沙箱隔离Gradle 任务目前不在隔离工作空间中执行这是遗留问题。工作单元的典型例子包括Gradle 任务动作task actions与构件变换artifact transforms构建脚本的编译build script compilation构建脚本的依赖访问器生成generation of dependency accessorsMaven goals执行引擎当前并未直接用于执行 Maven goals但其本身没有任何 Gradle 特有内容会阻止这种用途。2.3 识别工作本地身份Identity与构建缓存键Build Cache Key为支持安全、优化的执行执行引擎需要识别工作单元。每个单元有两个标识符身份Identity在当前执行作用域如整个 Gradle 构建树内本地唯一的工作标识。对于任务身份就是任务路径如:subproject:taskName对于其他类型的工作身份是由其不可变输入计算出的哈希。构建缓存键Build Cache Key用于跨时间与空间存储和检索工作输出的全局标识符使用全部输入计算。2.4 执行状态Execution State工作单元的执行状态由以下部分组成输入inputs实现本身——工作实现的完全限定类名FQCN如org.gradle.api.tasks.compile.JavaCompile及其 classpath 的 classloader 哈希输入属性值的value snapshot文件输入的指纹fingerprint。输出outputs输出文件的文件系统快照file-system snapshot执行是否成功输出的来源origin本次构建新产生或复用了之前构建的结果。历史执行状态按工作的身份索引存储在**执行历史execution history**中。执行历史对应示意图中的 Execution History 存储节点其在源码中的序列化实现可参考 platforms/core-execution/execution/src/main/java/org/gradle/internal/execution/history/impl/FileSystemSnapshotSerializer.java。2.5 快照Snapshot与指纹Fingerprint执行状态的捕获通过对工作的输入和输出做**快照snapshotting与指纹fingerprinting**完成通常发生在执行前后。快照Snapshotting为输入或输出在某个时间点创建其**原样状态verbatim state**的不可变记录。快照之后可以用来与同一对象在另一时刻的快照对比以检测是否发生了修改。指纹Fingerprinting捕获输入的规范化状态normalized state。两者本质都是数据的指纹区别在于快照代表数据的原样状态指纹代表按预期用途规范化后的状态更精确地说是未规范化指纹与规范化指纹但文档沿用了这两个更简洁的术语。规范化Normalization帮助忽略无关信息、提升缓存命中率它取决于输入的用途usage同一批.class文件作为编译任务的编译 classpath 与作为运行测试的运行时 classpath 时会被不同地规范化。而输出从不被规范化。三、执行引擎的流水线步骤管线Step Pipeline执行引擎采用**嵌套步骤的流水线pipeline of nested steps**来处理执行请求这种结构与 Servlet 应用中的过滤器链filter chain类似。单个步骤的执行通常遵循以下配方步骤接收被执行的工作单元以及一个包含前面步骤收集信息的不可变数据对象context上下文步骤可以做一些有意义的工作例如在外部服务中查找关于工作单元的信息、修改工作空间等步骤决定是否调用流水线中的下一步将 context 传递给它——可以原样传递也可以附加更多数据步骤也可以短路short-circuit不调用下一步而提前返回步骤返回一个结果result描述发生了什么的不变数据对象。它可以是下一步返回的结果本身、附加了新数据的增强版结果或完全由本步骤创建的新对象。此外步骤可以修改工作空间Can modify workspace数据既可以附加到 context 上输入性质也可以附加到 result 上输出性质——这些信息均直接标注在执行引擎示意图中。四、执行引擎的优化手段当输入定义良好的工作单元时执行引擎可以采用以下安全优化来尽可能高效地产出输出身份缓存Identity Caching如果工作在当前工具调用上下文中已用相同输入执行过则查询内存缓存获取结果。身份缓存仅对构件变换可用见下文延迟执行。Up-to-Date 检查Up-to-Date Checks即增量构建如果工作的执行状态是up-to-date则跳过执行。构建缓存Build Cache如果输出在本地不是最新的引擎先在本地缓存中检索已存储的结果必要时再查远程缓存。执行Execution如果在构建缓存中未找到结果则真正执行工作。4.1 来源元数据Origin Metadata每个产生的结果都带有来源元数据一组键值对描述该结果由哪个构建创建、耗时多久以及关联的缓存键。通过查询来源元数据可以判断结果是本次构建产生的还是从之前的构建复用的。4.2 Up-to-Date 检查增量构建的实现通过将工作单元执行前的状态与上一次执行后的状态进行对比输入值变化比较输入值属性的ValueSnapshot输入文件变化比较输入文件属性的指纹输出变化比较输出属性的快照。如果输入和输出都没有变化则无需执行直接跳过。[!NOTE] 文档特意提示增量**构建incremental build与增量工作incremental work**指代不同种类的增量性术语上应逐步弃用incremental build。4.3 构建缓存的读写流程如果工作的执行状态已过期则尝试从构建缓存加载输出允许使用缓存时先查本地缓存本地缓存没有对应缓存键的条目时再问远程缓存缓存命中时删除并解包结果到输出位置同时清理本地状态缓存未命中或不允许从缓存加载时继续执行执行结束后检查是否允许存入本地缓存允许时同时存入本地与远程缓存。[!NOTE] 对于任务存在一个内部机制可以阻止将已执行任务的结果存入构建缓存。这一内部特性仅被 Develocity 的预测性测试选择predictive test selection优化所使用。五、执行模式可变工作与不可变工作执行引擎支持两类工作可变mutable与不可变immutable。可变工作可根据与上次执行相比哪些输入发生了变化选择增量或非增量执行。不可变工作Immutable Work全部输入都是不可变输入完整输入集定义了工作。例如访问器生成、非增量构件变换。可变工作Mutable Work只有一部分输入是不可变输入其余是可能在不同执行之间变化的可变输入。例如任务与增量构件变换。工作在其工作空间中执行即在其工作空间中产出输出。工作空间是由身份分配给工作的专用目录在工作空间内的执行受锁保护防止多个工作单元相互冲突Gradle 任务因历史原因没有独占工作空间与互斥两个 Gradle daemon 在同一构建上运行同一任务时可能冲突。关键规则如果不可变输入相比上一次本地执行发生了变化引擎会将工作视为一个新的、不同的单元并分配不同的工作空间而可变输入的变化不会改变可变工作的身份因此它会在同一工作空间中执行任务目前例外其身份是完整任务路径计划改为与构件变换一样在工作空间中执行。5.1 工作空间分配Workspace Allocation可变工作只要只有可变输入在变化就会在**同一个可变工作空间mutable workspace**中执行因此得名。不可变工作在执行时被分配一个临时工作空间目录执行结束或从缓存加载结果后该工作空间目录被原子性地移动到不可变工作空间immutable workspace此后不再被修改。5.2 增量执行Incremental Execution对于可变工作可变输入有以下三种行为非增量Non-incremental属性值的任何变化都触发工作的完全重建。增量Incremental在任务与变换中用Incremental标注属性值的变化可以触发工作的增量执行由工作负责更新任何先前的输出。为此执行引擎会向动作提供自上次在同一工作空间执行以来任何增量输入的变化列表。主要Primary在任务中用SkipWhenEmpty标注与增量输入相同额外特性是如果所有主要输入都为空则跳过工作执行并删除其输出。如果选择非增量执行可变工作空间首先被清理任务因历史原因不清理一些增量任务未声明自己是增量的直接删除输出会是破坏性变更。5.3 延迟执行构件变换Artifact Transforms的特例具有相同身份的工作在单次构建中通常只执行一次。但构件变换有些特殊它们定义在消费项目中因此相同身份的变换可能在同一次构建中被多次、且往往并发地调用例如每个需要 Guava 的子项目都调用最小化 Guava JAR这个变换。为处理这种场景并避免竞态条件执行引擎提供了延迟deferred路径此模式下引擎立即返回一个DeferrableT它要么已持有缓存结果要么可以在稍后同步完成。工作完成后结果被存入身份缓存通过同步、非延迟方式执行时身份缓存被忽略。六、遗留特例Gradle 任务Legacy: The Special Case of Gradle Tasks文档明确指出适用于其他工作单元的一些不变量尚未适用于任务这主要是历史原因应当被解决。6.1 身份Identity任务的身份是其在构建中的路径如:project-name:taskName。关键点是该身份与非增量输入无关。对于非增量任务当某个非增量输入变化时先前的输出仍会呈现给动作清理责任由动作承担对于增量任务当非增量输入变化时执行引擎会自动清理输出。计划是将此行为扩展到非增量任务或让它们通过不可变工作空间执行但有些任务没有声明自己是增量的却依赖更新输出的能力——典型例子是 Gradle 的 Kotlin 编译任务简单强制这一变更会让它们失去增量能力。6.2 无独占工作空间No Exclusive Workspace任务没有自己的工作空间其文件输出可以指向文件系统上的任意位置实践中通常只产生单个目录或文件。未来计划让任务更像构件变换要求其在工作空间内产出输出。6.3 重叠输出Overlapping Outputs任务允许在其他任务也产出输出的目录中产出输出这使确定哪个输出文件由哪次执行产生变得困难也让并行执行不安全。因此对于检测到产生重叠输出的任务执行引擎会禁用执行优化。未来计划禁止任务产生重叠输出不过为将来支持 Maven goals——其重叠输出很常见——引擎中很可能保留一定程度的支持。七、快照与指纹的底层实现snapshots/README.md 提供了快照与指纹的详细技术说明。7.1 快照的三种形态快照是某些数据状态的简洁表示用于检查对应数据是否发生变化使用密码学哈希表示数据状态标量非文件输入由ValueSnapshotter捕获为ValueSnapshot对象单个文件系统位置可通过FileSystemAccess获取为FileSystemLocationSnapshot——包含该文件系统对象的绝对路径与其内容的哈希文件集合由FileCollectionSnapshotter捕获为FileSystemSnapshot可以有多条根roots而FileSystemLocationSnapshot只有一条根。上述类型在源码中均有对应实现例如 platforms/core-execution/snapshots/src/main/java/org/gradle/internal/snapshot/FileSystemLocationSnapshot.java 与 platforms/core-execution/snapshots/src/main/java/org/gradle/internal/snapshot/FileSystemSnapshot.java。7.2 哈希算法与 Merkle 树计算文件内容与标量输入的快照/指纹时使用MD5密码学哈希算法同一算法也用于计算工作单元的标识符如构建缓存键。为什么选 MD5MD5 在安全层面早已被攻破但此处目标不是对抗恶意意图而是避免意外碰撞MD5 对此足够强它速度极快、JVM 上普遍可用且每个哈希仅占 16 字节相比 SHA120 字节或 SHA25632 字节更省内存。文档同时指出可以使用其他密码学哈希让哈希可配置是合理的BLAKE 系列哈希族在性能上很有前景但仍需更多研究。非密码学哈希如 xxHash、MurmurHash 虽然显著更快但缺少所需的天文级抗碰撞性。复杂输入使用Merkle 树生成单一哈希将各组成部分的哈希再哈希得到整体的哈希。对应实现见 platforms/core-execution/snapshots/src/main/java/org/gradle/internal/snapshot/MerkleDirectorySnapshotBuilder.java。7.3 虚拟文件系统Virtual File-SystemVFS执行引擎经常需要以快照形式获取文件系统状态。若每次都重新读取整个文件层级效率过低因此文件系统状态被缓存在**虚拟文件系统VFS**中VFS只存储正在运行的构建的目录层级信息——不会保留构建根目录及任何 included build 根目录之外的文件系统对象信息之前构建的数据也可保留一段时间。VFS 使用FileSystemNode组成的高效稀疏树数据结构存储该结构允许在请求父目录快照时复用已拍摄的快照还支持存储过滤后的快照例如只请求目录层级中的*.java文件。对应实现见 platforms/core-execution/snapshots/src/main/java/org/gradle/internal/snapshot/FileSystemNode.java。VFS 不直接暴露入口是FileSystemAccess服务见 platforms/core-execution/snapshots/src/main/java/org/gradle/internal/vfs/FileSystemAccess.java它有多个read()方法获取文件与目录快照。VFS 的整体结构可参考 虚拟文件系统示意图。Gradle 虚拟文件系统VFS结构示意图变更跟踪Change Tracking为保证 VFS 正确缓存文件系统状态必须在文件系统被修改之前使 VFS 的相关部分失效。假设在构建运行期间VFS 跟踪区域的文件系统变更总是会被失效处理因此修改文件系统的代码应包裹在FileSystemAccess.write()中或在变更生效前调用FileSystemAccess.invalidate()。文件系统监听File-System Watching为了跟踪构建之间的修改VFS 在支持的平台上监听文件系统发生修改时VFS 中任何可能过期的数据部分都会被丢弃。对应机制见 文件系统监听示意图。当文件系统监听不可用时构建期间收集的所有 VFS 数据都会被丢弃。VFS 与执行引擎整体上不区分直接访问的内容与通过符号链接symlink访问的内容但文件系统监听无法可靠地通知符号链接内容的变更因此在构建结束时即使启用了文件系统监听也会将通过符号链接访问的内容从 VFS 中丢弃。缓存文件哈希Caching File Hashes实际的文件内容哈希由FileHasher处理文件哈希在内存与磁盘上都有缓存。这些缓存使用文件修改日期与大小作为启发式信号判断文件是否被修改。这意味着即使由于某种原因使某文件的 VFS 快照失效只要文件在真实文件系统中未变仍可通过缓存的哈希廉价地重新创建快照。八、输入规范化Input Normalization并非所有输入都与工作相关利用这一点可获得更好的性能。文档给出的经典例子是Java 编译任务的换行符源文件中的换行符无关紧要无论使用\n还是\r\n都不影响编译结果因此换行符的变化不应触发重新编译之前的.class文件应被视为 up-to-date。忽略此类差异还允许通过远程构建缓存跨操作系统复用缓存编译结果。除了源文件的换行符规范化Java 编译还可声明编译 classpath 通过ABI 提取ABI extraction进行规范化——输入哈希基于 classpath 提取出的 ABI 而非原始文件内容计算从而只要依赖差异不影响 ABI就能复用已有编译结果。[!NOTE] 输入规范化目前仅对文件输入可用但如需也可引入标量输入规范化。8.1 指纹Fingerprints规范化后的输入被捕获为指纹FileSystemLocationFingerprint见 platforms/core-execution/snapshots/src/main/java/org/gradle/internal/fingerprint/FileSystemLocationFingerprint.java。这些对象与快照类似但携带的是规范化路径而非绝对路径捕获的是规范化内容的哈希而非原样内容的哈希。例如计算 Java 源文件指纹时先把所有换行符替换为\n再哈希内容并且只捕获从源目录起的相对路径。对于FileCollection逐文件指纹存储在以文件绝对路径为索引的Map中——即指纹不保留快照那样的文件系统层级结构这是历史选择可以改变。8.2 规范化策略Normalization Strategies文件集合指纹通过**指纹策略fingerprinting strategy**对文件系统快照中的文件与路径做指纹化生成。一个指纹策略可以多种方式规范化文件输入归档理解archive comprehension将归档视为与目录等价可遍历其元素忽略文件顺序、时间戳与权限等元数据模式过滤pattern filtering将范围限制到某些模式的文件如 Java 编译 classpath 规范化中的*.class注意此过滤是对输入FileCollection本身已有过滤的补充FileCollection级过滤已体现在文件集合快照中空目录过滤empty directory filtering用IgnoreEmptyDirectories忽略指纹中的空目录路径规范化path normalization可忽略每个文件路径的部分或全部如任务属性上使用的PathSensitive(RELATIVE)顺序规范化order normalization通过按某种可复现顺序排序来忽略文件顺序根元素的顺序可以与后代元素的顺序不同地处理这由FingerprintHashingStrategy负责内容规范化content normalization每个文件可单独规范化例如 JVM 运行时 classpath 上的.properties文件可被解析以忽略注释等。8.3 路径规范化Path Normalization大多数输入文件属性使用路径规范化并完全忽略条目顺序通过输入属性上的PathSensitive注解实现选项包括选项含义ABSOLUTE不忽略路径使用每个条目的完整绝对路径RELATIVE忽略从根开始的路径NAME_ONLY只考虑文件名IGNORE完全忽略路径8.4 内容规范化Content NormalizationGradle 对Java 编译 classpath 与 JVM 运行时 classpath特殊处理对它们规范内容和路径根元素顺序不规范化但JAR 与类目录内部条目的顺序被忽略。CompileClasspath假设文件是 ZIP将其视为目录层级保留根元素顺序忽略子树中条目的顺序过滤.class文件使用每个.class文件提取出的 ABI计算内容哈希。Classpath即运行时 classpath假设文件是 ZIP 并将其视为目录层级递归进行保留根元素顺序忽略子树中条目的顺序应用来自project.normalization.runtimeClasspath的过滤器根据project.normalization.runtimeClasspath规范化.properties与META-INF内容。另外标记了NormalizeLineEndings通常是源代码的输入会做换行符规范化。8.5 比较指纹Comparing Fingerprints指纹策略还会决定结果文件集合指纹的指纹比较策略fingerprint compare strategy该比较策略用于up-to-date 检查时比较两个文件集合指纹。九、工作验证Work ValidationWork Validation.md 讲解的工作验证是检查工作单元任务、变换在构建逻辑中是否被正确定义的过程。它专门关注工作如何被定义、其输入与输出是否被正确接线执行期间发生的运行时错误不在此处处理。9.1 验证的两种形式静态验证Static validation发生在插件开发期间通过 ASM 访问构建逻辑编译后的.class文件进行由ValidatePlugins任务执行。运行时验证Runtime validation在工作单元执行期间发生使用反射信息。执行引擎在ValidateStep中调用运行时验证。对应实现可参考执行引擎步骤实现 platforms/core-execution/execution/src/main/java/org/gradle/internal/execution/steps/ValidateStep.java 及其测试 platforms/core-execution/execution/src/test/groovy/org/gradle/internal/execution/steps/ValidateStepTest.groovy。两种形式都关心工作及其属性是否具有正确的注解与方法签名但可用数据的来源与详细程度不同。9.2 嵌套属性验证的关键差异两者最大的区别在于嵌套属性的类型如何被验证。考虑任务的如下属性Nested PropertyAnInterfaceType getValue();静态验证只能知道value属性将是AnInterfaceType的某个实现因此只能验证AnInterfaceType本身运行时验证则知道value属性中存储的对象的实际类型例如SomeImplementationType。该类型实现了AnInterfaceType但它可能还定义了自己的更多属性这些属性也需要被验证。因此运行时验证可以产生静态验证已通过的工作类型的警告与错误。[!NOTE] 运行时验证还可以验证通过运行时 API为任务注册的属性。9.3 验证内容文档同时指出由于历史原因目前只对任务实现了验证但所有用户定义的工作类型都可受益于验证运行时任务验证实现在TaskExecution.validate()中。十、总结与深入阅读路径Gradle 的 Core Execution 平台用一套统一模型解决了如何在并发、可缓存、可增量的环境下安全高效地执行工作这一核心问题执行引擎platforms/core-execution/execution/README.md负责以嵌套步骤流水线执行工作单元组合身份缓存、up-to-date 检查、构建缓存与增量执行等优化快照与指纹platforms/core-execution/snapshots/README.md负责通过 MD5 Merkle 树、VFS 与规范化策略为执行状态捕获可靠且可复用的证据工作验证platforms/core-execution/Work Validation.md通过静态ValidatePlugins ASM与运行时ValidateStep 反射两种途径保证工作定义的正确性。若想继续深入推荐按以下顺序阅读源码执行引擎实现与步骤管线platforms/core-execution/execution/src/main/java/org/gradle/internal/execution/steps快照与虚拟文件系统platforms/core-execution/snapshots/src/main/java/org/gradle/internal/snapshot 与 platforms/core-execution/snapshots/src/main/java/org/gradle/internal/vfs输入规范化策略platforms/core-execution/normalization-api 与 platforms/core-execution/normalization-java哈希与文件监听platforms/core-execution/hashing、platforms/core-execution/file-watching。理解这些机制是深入理解 Gradle 增量构建、远程构建缓存与构件变换调优的基础。赞分享构建工具开发工具【免费下载链接】gradleAdaptable, fast automation for all项目地址https://gitcode.com/gh_mirrors/gr/gradle点击查看免费下载相关推荐Nacos 任务执行引擎Task Execution深度解析延迟任务、执行任务与领域调度机制Nacos 任务执行引擎Task Execution深度解析延迟任务、执行任务与领域调度机制 本文以 Nacos 官方设计规范 Foundation Ta后端微服务配置中心服务注册发现云原生Gradle 快照与指纹识别Snapshotting Fingerprinting原理与实践深度解析Gradle 快照与指纹识别Snapshotting Fingerprinting原理与实践深度解析 本文围绕 Gradle 执行平台Core Exe构建工具开发工具EIP-7886 延迟执行Delayed Execution深度解析将区块验证与执行解耦解锁异步验证与更高吞吐EIP 7886 延迟执行Delayed Execution深度解析将区块验证与执行解耦解锁异步验证与更高吞吐 导读 EIP 7886Delayed区块链文档Web3上一篇揭秘FreeGPT35-Vercel工作原理无登录ChatGPT Web API调用核心技术下一篇HELK Sigma规则应用指南如何快速创建和部署威胁检测规则创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门