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

JavaScript系列(50)--编译器实现详解

JavaScript编译器实现详解 🔨

今天,让我们深入探讨JavaScript编译器的实现。编译器是一个将源代码转换为目标代码的复杂系统,通过理解其工作原理,我们可以更好地理解JavaScript的执行过程。

编译器基础概念 🌟

💡 小知识:编译器通常包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等阶段。每个阶段都有其特定的任务和挑战。

词法分析器实现 📊

// 1. Token类型定义
const TokenType = {// 关键字FUNCTION: 'FUNCTION',RETURN: 'RETURN',IF: 'IF',ELSE: 'ELSE',// 标识符和字面量IDENTIFIER: 'IDENTIFIER',NUMBER: 'NUMBER',STRING: 'STRING',// 运算符PLUS: 'PLUS',MINUS: 'MINUS',MULTIPLY: 'MULTIPLY',DIVIDE: 'DIVIDE',// 分隔符LEFT_PAREN: 'LEFT_PAREN',RIGHT_PAREN: 'RIGHT_PAREN',LEFT_BRACE: 'LEFT_BRACE',RIGHT_BRACE: 'RIGHT_BRACE',SEMICOLON: 'SEMICOLON',// 其他EOF: 'EOF'
};// 2. Token类
class Token {constructor(type, value, line, column) {this.type = type;this.value = value;this.line = line;this.column = column;}
}// 3. 词法分析器
class Lexer {constructor(source) {this.source = source;this.tokens = [];this.start = 0;this.current = 0;this.line = 1;this.column = 1;}scanTokens() {while (!this.isAtEnd()) {this.start = this.current;this.scanToken();}this.tokens.push(new Token(TokenType.EOF, null,this.line, this.column));return this.tokens;}scanToken() {const c = this.advance();switch (c) {// 单字符tokencase '(': this.addToken(TokenType.LEFT_PAREN); break;case ')': this.addToken(TokenType.RIGHT_PAREN); break;case '{': this.addToken(TokenType.LEFT_BRACE); break;case '}': this.addToken(TokenType.RIGHT_BRACE); break;case ';': this.addToken(TokenType.SEMICOLON); break;// 运算符case '+': this.addToken(TokenType.PLUS); break;case '-': this.addToken(TokenType.MINUS); break;case '*': this.addToken(TokenType.MULTIPLY); break;case '/':if (this.match('/')) {// 单行注释while (this.peek() !== '\n' && !this.isAtEnd()) {this.advance();}} else {this.addToken(TokenType.DIVIDE);}break;// 忽略空白字符case ' ':case '\r':case '\t':break;case '\n':this.line++;this.column = 1;break;// 字符串case '"': this.string(); break;default:if (this.isDigit(c)) {this.number();} else if (this.isAlpha(c)) {this.identifier();} else {throw new Error(`Unexpected character: ${c} at line ${this.line}`);}break;}}// 辅助方法advance() {this.column++;return this.source.charAt(this.current++);}match(expected) {if (this.isAtEnd()) return false;if (this.source.charAt(this.current) !== expected) return false;this.current++;return true;}peek() {if (this.isAtEnd()) return '\0';return this.source.charAt(this.current);}isAtEnd() {return this.current >= this.source.length;}addToken(type, literal = null) {const text = this.source.substring(this.start, this.current);this.tokens.push(new Token(type, literal || text, this.line, this.column));}
}

语法分析器实现 🚀

// 1. AST节点类型
class ASTNode {constructor(type) {this.type = type;}
}// 2. 表达式节点
class BinaryExpr extends ASTNode {constructor(left, operator, right) {super('BinaryExpr');this.left = left;this.operator = operator;this.right = right;}
}class UnaryExpr extends ASTNode {constructor(operator, right) {super('UnaryExpr');this.operator = operator;this.right = right;}
}class LiteralExpr extends ASTNode {constructor(value) {super('LiteralExpr');this.value = value;}
}// 3. 语法分析器
class Parser {constructor(tokens) {this.tokens = tokens;this.current = 0;}parse() {try {return this.expression();} catch (error) {console.error('Parse error:', error);return null;}}expression() {return this.term();}term() {let expr = this.factor();while (this.match(TokenType.PLUS, TokenType.MINUS)) {const operator = this.previous();const right = this.factor();expr = new BinaryExpr(expr, operator, right);}return expr;}factor() {let expr = this.unary();while (this.match(TokenType.MULTIPLY, TokenType.DIVIDE)) {const operator = this.previous();const right = this.unary();expr = new BinaryExpr(expr, operator, right);}return expr;}unary() {if (this.match(TokenType.MINUS)) {const operator = this.previous();const right = this.unary();return new UnaryExpr(operator, right);}return this.primary();}primary() {if (this.match(TokenType.NUMBER)) {return new LiteralExpr(parseFloat(this.previous().value));}if (this.match(TokenType.LEFT_PAREN)) {const expr = this.expression();this.consume(TokenType.RIGHT_PAREN,"Expect ')' after expression.");return expr;}throw new Error('Expect expression.');}// 辅助方法match(...types) {for (const type of types) {if (this.check(type)) {this.advance();return true;}}return false;}check(type) {if (this.isAtEnd()) return false;return this.peek().type === type;}advance() {if (!this.isAtEnd()) this.current++;return this.previous();}isAtEnd() {return this.peek().type === TokenType.EOF;}peek() {return this.tokens[this.current];}previous() {return this.tokens[this.current - 1];}
}

代码生成器实现 💻

// 1. 代码生成器
class CodeGenerator {constructor() {this.output = '';this.indent = 0;}generate(ast) {return this.visitNode(ast);}visitNode(node) {switch (node.type) {case 'BinaryExpr':return this.generateBinaryExpr(node);case 'UnaryExpr':return this.generateUnaryExpr(node);case 'LiteralExpr':return this.generateLiteralExpr(node);default:throw new Error(`Unknown node type: ${node.type}`);}}generateBinaryExpr(node) {const left = this.visitNode(node.left);const right = this.visitNode(node.right);return `(${left} ${node.operator.value} ${right})`;}generateUnaryExpr(node) {const right = this.visitNode(node.right);return `(${node.operator.value}${right})`;}generateLiteralExpr(node) {return node.value.toString();}
}// 2. 优化器
class Optimizer {optimize(ast) {return this.visitNode(ast);}visitNode(node) {switch (node.type) {case 'BinaryExpr':return this.optimizeBinaryExpr(node);case 'UnaryExpr':return this.optimizeUnaryExpr(node);case 'LiteralExpr':return node;default:throw new Error(`Unknown node type: ${node.type}`);}}optimizeBinaryExpr(node) {const left = this.visitNode(node.left);const right = this.visitNode(node.right);// 常量折叠if (left.type === 'LiteralExpr' && right.type === 'LiteralExpr') {const result = this.evaluateConstExpr(left.value,node.operator.value,right.value);return new LiteralExpr(result);}return new BinaryExpr(left, node.operator, right);}evaluateConstExpr(left, operator, right) {switch (operator) {case '+': return left + right;case '-': return left - right;case '*': return left * right;case '/': return left / right;default:throw new Error(`Unknown operator: ${operator}`);}}
}// 3. 源码映射生成器
class SourceMapGenerator {constructor() {this.mappings = [];this.sources = [];this.names = [];}addMapping(generated, original, source, name) {this.mappings.push({generated,original,source,name});}generate() {return {version: 3,file: 'output.js',sourceRoot: '',sources: this.sources,names: this.names,mappings: this.encodeMappings()};}encodeMappings() {// 实现VLQ编码return this.mappings.map(mapping => {return [mapping.generated.line,mapping.generated.column,mapping.original.line,mapping.original.column].join(',');}).join(';');}
}

实际应用场景 💼

// 1. 简单计算器编译器
class CalculatorCompiler {constructor() {this.lexer = null;this.parser = null;this.generator = null;}compile(source) {// 词法分析this.lexer = new Lexer(source);const tokens = this.lexer.scanTokens();// 语法分析this.parser = new Parser(tokens);const ast = this.parser.parse();// 优化const optimizer = new Optimizer();const optimizedAst = optimizer.optimize(ast);// 代码生成this.generator = new CodeGenerator();return this.generator.generate(optimizedAst);}
}// 2. DSL编译器
class DSLCompiler {constructor(grammar) {this.grammar = grammar;this.lexer = null;this.parser = null;}compile(source) {// 根据语法规则生成词法分析器this.lexer = this.createLexer(source);const tokens = this.lexer.scanTokens();// 根据语法规则生成语法分析器this.parser = this.createParser(tokens);const ast = this.parser.parse();// 生成目标代码return this.generateCode(ast);}createLexer(source) {// 根据语法规则创建自定义词法分析器return new CustomLexer(source, this.grammar.tokens);}createParser(tokens) {// 根据语法规则创建自定义语法分析器return new CustomParser(tokens, this.grammar.rules);}generateCode(ast) {// 根据AST生成目标代码const generator = new CustomCodeGenerator(this.grammar.target);return generator.generate(ast);}
}// 3. 模板编译器
class TemplateCompiler {constructor() {this.cache = new Map();}compile(template) {if (this.cache.has(template)) {return this.cache.get(template);}const tokens = this.tokenize(template);const ast = this.parse(tokens);const code = this.generate(ast);const render = new Function('data', code);this.cache.set(template, render);return render;}tokenize(template) {const tokens = [];let current = 0;while (current < template.length) {if (template[current] === '{' && template[current + 1] === '{') {// 处理表达式current += 2;let expr = '';while (current < template.length && !(template[current] === '}' && template[current + 1] === '}')) {expr += template[current];current++;}tokens.push({type: 'expression',value: expr.trim()});current += 2;} else {// 处理文本let text = '';while (current < template.length && !(template[current] === '{' && template[current + 1] === '{')) {text += template[current];current++;}tokens.push({type: 'text',value: text});}}return tokens;}
}

性能优化技巧 ⚡

// 1. 缓存优化
class CompilerCache {constructor() {this.tokenCache = new Map();this.astCache = new Map();this.codeCache = new Map();}getTokens(source) {const hash = this.hashSource(source);if (this.tokenCache.has(hash)) {return this.tokenCache.get(hash);}const tokens = new Lexer(source).scanTokens();this.tokenCache.set(hash, tokens);return tokens;}getAST(tokens) {const hash = this.hashTokens(tokens);if (this.astCache.has(hash)) {return this.astCache.get(hash);}const ast = new Parser(tokens).parse();this.astCache.set(hash, ast);return ast;}getCode(ast) {const hash = this.hashAST(ast);if (this.codeCache.has(hash)) {return this.codeCache.get(hash);}const code = new CodeGenerator().generate(ast);this.codeCache.set(hash, code);return code;}hashSource(source) {// 实现源码哈希return source.length + source.slice(0, 100);}hashTokens(tokens) {// 实现tokens哈希return tokens.map(t => t.type + t.value).join('');}hashAST(ast) {// 实现AST哈希return JSON.stringify(ast);}
}// 2. 并行处理
class ParallelCompiler {constructor(workerCount = navigator.hardwareConcurrency) {this.workers = [];this.initWorkers(workerCount);}async initWorkers(count) {for (let i = 0; i < count; i++) {const worker = new Worker('compiler-worker.js');this.workers.push(worker);}}async compile(sources) {const chunks = this.splitSources(sources);const promises = chunks.map((chunk, index) => {return new Promise((resolve, reject) => {const worker = this.workers[index % this.workers.length];worker.onmessage = e => resolve(e.data);worker.onerror = reject;worker.postMessage({ type: 'compile', sources: chunk });});});const results = await Promise.all(promises);return this.mergeResults(results);}splitSources(sources) {// 将源码分割成多个块const chunkSize = Math.ceil(sources.length / this.workers.length);const chunks = [];for (let i = 0; i < sources.length; i += chunkSize) {chunks.push(sources.slice(i, i + chunkSize));}return chunks;}
}// 3. 增量编译
class IncrementalCompiler {constructor() {this.cache = new CompilerCache();this.dependencies = new Map();this.modifiedFiles = new Set();}markFileModified(file) {this.modifiedFiles.add(file);// 标记依赖文件const deps = this.dependencies.get(file) || new Set();for (const dep of deps) {this.markFileModified(dep);}}async compile(files) {const results = new Map();for (const file of files) {if (!this.modifiedFiles.has(file) && this.cache.has(file)) {results.set(file, this.cache.get(file));continue;}const result = await this.compileFile(file);results.set(file, result);this.cache.set(file, result);this.modifiedFiles.delete(file);}return results;}async compileFile(file) {const source = await this.readFile(file);const tokens = this.cache.getTokens(source);const ast = this.cache.getAST(tokens);// 收集依赖this.collectDependencies(file, ast);return this.cache.getCode(ast);}collectDependencies(file, ast) {const deps = new Set();this.traverseAST(ast, node => {if (node.type === 'Import') {deps.add(node.source);}});this.dependencies.set(file, deps);}
}

最佳实践建议 💡

  1. 错误处理和恢复
// 1. 错误收集器
class ErrorCollector {constructor() {this.errors = [];}addError(error) {this.errors.push({message: error.message,line: error.line,column: error.column,phase: error.phase});}hasErrors() {return this.errors.length > 0;}getErrors() {return this.errors;}clear() {this.errors = [];}
}// 2. 错误恢复策略
class ErrorRecovery {static recoverFromSyntaxError(parser) {// 跳过到下一个同步点while (!parser.isAtEnd()) {if (parser.match(TokenType.SEMICOLON)) return;if (parser.peek().type === TokenType.RIGHT_BRACE) return;parser.advance();}}
}// 3. 诊断信息生成
class DiagnosticReporter {constructor(source) {this.source = source;this.lines = source.split('\n');}report(error) {const line = this.lines[error.line - 1];const pointer = ' '.repeat(error.column - 1) + '^';return [`Error: ${error.message}`,`  at line ${error.line}, column ${error.column}`,line,pointer,`Phase: ${error.phase}`].join('\n');}
}

结语 📝

JavaScript编译器的实现是一个复杂但有趣的主题。通过本文,我们学习了:

  1. 编译器的基本架构和工作原理
  2. 词法分析和语法分析的实现
  3. 代码生成和优化技术
  4. 性能优化策略
  5. 错误处理和最佳实践

💡 学习建议:在实现编译器时,要注意模块化设计和错误处理。合理使用缓存和优化策略,可以显著提升编译性能。同时,良好的错误提示对于开发者体验至关重要。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

相关文章:

JavaScript系列(50)--编译器实现详解

JavaScript编译器实现详解 &#x1f528; 今天&#xff0c;让我们深入探讨JavaScript编译器的实现。编译器是一个将源代码转换为目标代码的复杂系统&#xff0c;通过理解其工作原理&#xff0c;我们可以更好地理解JavaScript的执行过程。 编译器基础概念 &#x1f31f; &…...

大数据相关职位 职业进阶路径

大数据相关职位 & 职业进阶路径 &#x1f4cc; 大数据相关职位 & 职业进阶路径 大数据领域涵盖多个方向&#xff0c;包括数据工程、数据分析、数据治理、数据科学等&#xff0c;每个方向的进阶路径有所不同。以下是大数据相关职位的详细解析及其职业进阶关系。 &#…...

基础项目实战——学生管理系统(c++)

目录 前言一、功能菜单界面二、类与结构体的实现三、录入学生信息四、删除学生信息五、更改学生信息六、查找学生信息七、统计学生人数八、保存学生信息九、读取学生信息十、打印所有学生信息十一、退出系统十二、文件拆分结语 前言 这一期我们来一起学习我们在大学做过的课程…...

C++,STL,【目录篇】

文章目录 一、简介二、内容提纲第一部分&#xff1a;STL 概述第二部分&#xff1a;STL 容器第三部分&#xff1a;STL 迭代器第四部分&#xff1a;STL 算法第五部分&#xff1a;STL 函数对象第六部分&#xff1a;STL 高级主题第七部分&#xff1a;STL 实战应用 三、写作风格四、…...

【Rust自学】15.3. Deref trait Pt.2:隐式解引用转化与可变性

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 15.3.1. 函数和方法的隐式解引用转化(Deref Coercion) 隐式解引用转化(Deref Coercion)是为函数和方法提供的一种便捷特性。 它的原理是…...

密码强度验证代码解析:C语言实现与细节剖析

在日常的应用开发中&#xff0c;密码强度验证是保障用户账户安全的重要环节。今天&#xff0c;我们就来深入分析一段用C语言编写的密码强度验证代码&#xff0c;看看它是如何实现对密码强度的多维度检测的。 代码整体结构 这段C语言代码主要实现了对输入密码的一系列规则验证&a…...

arkts bridge使用示例

接上一篇&#xff1a;arkui-x跨平台与android java联合开发-CSDN博客 本篇讲前端arkui如何与后端其他平台进行数据交互&#xff0c;接上一篇&#xff0c;后端os平台为Android java。 arkui-x框架提供了一个独特的机制&#xff1a;bridge。 1、前端接口定义实现 定义一个bri…...

LINUX部署微服务项目步骤

项目简介技术栈 主体技术&#xff1a;SpringCloud&#xff0c;SpringBoot&#xff0c;VUE2&#xff0c; 中间件&#xff1a;RabbitMQ、Redis 创建用户 在linux服务器home下创建用户qshh&#xff0c;用于后续本项目需要的环境进行安装配置 #创建用户 useradd 用户名 #设置登录密…...

zsh安装插件

0 zsh不仅在外观上比较美观&#xff0c;而且其具有强大的插件&#xff0c;如果不使用那就亏大了。 官方插件库 https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins 官方插件库并不一定有所有的插件&#xff0c;比如zsh-autosuggestions插件就不再列表里&#xff0c;下面演示zs…...

网站如何正式上线(运维详解)

因为平台原因&#xff0c;不能有太多链接&#xff0c;所以下文中链接都删除了&#xff0c;想访问的去原文链接&#xff1a;https://www.zhoudongqi.com/ TIPS 这篇文章是我自己运营运维的wordpess站点的经验总结&#xff0c;可以说十分详细&#xff0c;域名&#xff0c;服务器和…...

SQL server 数据库使用整理

标题&#xff1a;SQL server 数据库使用整理 1.字符串表名多次查询 2.读取SQL中Json字段中的值&#xff1a;JSON_VALUE&#xff08;最新版本支持&#xff0c;属性名大小写敏感&#xff09; 1.字符串表名多次查询 SELECT ROW_NUMBER() OVER (ORDER BY value ASC) rowid,value…...

【Rust自学】17.2. 使用trait对象来存储不同值的类型

喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 17.2.1. 需求 这篇文章以一个例子来介绍如何在Rust中使用trait对象来存储不同值的类型。 …...

初始化mysql报错cannot open shared object file: No such file or directory

报错展示 我在初始化msyql的时候报错&#xff1a;mysqld: error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory 解读&#xff1a; libaio包的作用是为了支持同步I/O。对于数据库之类的系统特别重要&#xff0c;因此…...

2025年1月22日(网络编程)

系统信息&#xff1a; ubuntu 16.04LTS Raspberry Pi Zero 2W 系统版本&#xff1a; 2024-10-22-raspios-bullseye-armhf Python 版本&#xff1a;Python 3.9.2 已安装 pip3 支持拍摄 1080p 30 (1092*1080), 720p 60 (1280*720), 60/90 (640*480) 已安装 vim 已安装 git 学习…...

Jason配置环境变量

jason官网 https://jason-lang.github.io/ https://github.com/jason-lang/jason/releases 步骤 安装 Java 21 或更高版本 安装 Visual Studio Code 根据操作系统&#xff0c;请按照以下具体步骤操作 视窗 下载 Jason 的最新版本&#xff0c;选择“jason-bin-3.3.0.zip”…...

蓝桥杯python语言基础(7)——自定义排序和二分查找

目录 一、自定义排序 &#xff08;一&#xff09;sorted &#xff08;二&#xff09;list.sort 二、二分查找 bisect 一、自定义排序 &#xff08;一&#xff09;sorted sorted() 函数会返回一个新的已排序列表&#xff0c;而列表的 sort() 方法会直接在原列表上进行排序…...

(开源)基于Django+Yolov8+Tensorflow的智能鸟类识别平台

1 项目简介&#xff08;开源地址在文章结尾&#xff09; 系统旨在为了帮助鸟类爱好者、学者、动物保护协会等群体更好的了解和保护鸟类动物。用户群体可以通过平台采集野外鸟类的保护动物照片和视频&#xff0c;甄别分类、实况分析鸟类保护动物&#xff0c;与全世界各地的用户&…...

后盾人JS--闭包明明白白

延伸函数环境生命周期 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> <…...

redis的分片集群模式

redis的分片集群模式 1 主从哨兵集群的问题和分片集群特点 主从哨兵集群可应对高并发写和高可用性&#xff0c;但是还有2个问题没有解决&#xff1a; &#xff08;1&#xff09;海量数据存储 &#xff08;2&#xff09;高并发写的问题 使用分片集群可解决&#xff0c;分片集群…...

Kiwi 安卓浏览器本月停止维护,扩展功能迁移至 Edge Canary

IT之家 1 月 25 日消息&#xff0c;科技媒体 Android Authority 今天&#xff08;1 月 25 日&#xff09;发布博文&#xff0c;报道称 Kiwi 安卓浏览器将于本月停止维护&#xff0c;相关扩展支持功能已整合到微软 Edge Canary 浏览器中。 开发者 Arnaud42 表示 Kiwi 安卓浏览器…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...