CppCon 2014 学习:Lightning Talk: Writing a Python Interpreter for Fun and Profit
Lightning Talk: Writing a Python Interpreter for Fun and Profit
这段内容在讲的是 Python 的执行模型,尤其是 CPython 的工作流程。下面是逐步解析:
Python 是动态类型语言(Dynamically typed)
- 变量类型在运行时决定。
x = 42 # x 是 int x = "hello" # x 变成 str
Python 是解释型语言(Interpreted)
- Python 代码不是直接编译成机器码,而是先编译成字节码(bytecode),然后由解释器执行。
CPython 是官方实现
- CPython 是 python.org 提供的默认实现。
- 用 C语言 编写。
- 把
.py
文件编译成字节码(.pyc
),并由 CPython 解释器执行。
示例代码
Python 代码:
def func(a, b):c = a + bprint(c)return c
编译为字节码(Byte-code)
CPython 编译器会把上面的函数编译成类似这样的虚拟机指令(伪字节码):
PUSH a
PUSH b
BINARY_ADD # 相当于 c = a + b
POP c
PUSH c
PRINT_ITEM # 打印 c
PRINT_NEWLINE
PUSH c
RETURN_VALUE # 返回 c
解释说明:
- PUSH:把变量压入栈。
- BINARY_ADD:执行加法操作(从栈中弹出两个值,相加后再压入栈)。
- POP c:把加法结果赋值给
c
。 - PRINT_ITEM + PRINT_NEWLINE:打印变量。
- RETURN_VALUE:函数返回。
CPython 执行过程
- Python 源码被编译成字节码。
- 字节码被 CPython 的 虚拟机解释器执行(使用 eval loop)。
- 虚拟机使用 栈(stack-based VM) 执行操作。
总结
概念 | 说明 |
---|---|
动态类型 | 变量类型运行时决定 |
解释型语言 | 运行时解释执行,而不是编译成本地机器码 |
CPython | 官方 Python 实现,用 C 写的 |
字节码 | Python 编译后的一种中间表示,供解释器执行 |
虚拟机执行模型 | 使用栈结构逐步执行指令 |
你这段内容是在描述 Python 的对象模型、引用计数机制,以及如何通过嵌入 Python(如在 C++ 中)执行 Python 代码。我们来逐步解释:
一切皆对象(Everything is an object)
在 Python 中,所有东西都是对象:
类型 | 说明 |
---|---|
int | 整数对象 |
str | 字符串对象 |
list | 列表对象 |
dict | 字典对象 |
bool | 布尔对象 |
func | 函数对象 |
method | 方法对象 |
class | 类对象 |
module | 模块对象 |
无论是什么类型,在内存中都表现为一个对象结构,具有类型信息和引用计数。 |
引用计数(Reference Counting)
Python(CPython 实现)使用引用计数作为垃圾回收机制的一部分:
a = "Hello!"
b = a
解释:
"Hello!"
是一个字符串对象。a
引用它后,引用计数 = 1。b = a
后,引用计数变成 2。- 这就像 C++ 中的
std::shared_ptr
。
示意图:
a ─┐│▼+---------------+| "Hello!" | <-- 对象| count = 2 | <-- 引用计数| type = str |+---------------+▲│b ─┘
当引用计数为 0,CPython 会自动销毁该对象。
嵌入 Python:用 C++ 调用 Python
你下面的部分在描述 C++ 嵌入 Python 的场景(比如通过 CPython API):
// 假设是伪代码或嵌入式解释器伪逻辑
void test() {Ref module = vm.import(R"**(def pyfunc(a, b):return a + b)**");// MyInterpreter 执行 pyfunc
}
解释:
- 使用
vm.import()
可能是某个虚拟机对象载入 Python 模块。 - 多用于 C++ 嵌入式解释器或游戏引擎中嵌入脚本语言。
R"**( ... )**"
是原始字符串字面量,表示传入的是多行 Python 脚本。
这种嵌入方式常用于:- 嵌入 Python 脚本到 C++ 游戏/系统。
- 提供可扩展插件系统。
- 自动化测试、动态执行配置脚本等。
总结图解
Python 对象模型:
+---------------------+
| PyObject (头部) |
| - refcount | <-- 引用计数
| - type* (PyType) | <-- 类型信息
+---------------------+
| 数据 |
+---------------------+
总结要点
关键点 | 说明 |
---|---|
一切都是对象 | 所有变量/类型都是对象 |
引用计数 | 用来自动回收对象 |
引用共享 | 多个变量引用同一个对象 |
嵌入式解释器 | C++ 可以调用/执行 Python 代码 |
描述如何在 C++ 中嵌入 Python 并调用 Python 函数。虽然是伪代码(不是标准 CPython API),但表达的概念非常清楚。下面是逐行解释和你应该理解的核心概念:
场景:C++ 调用 Python 代码
你想实现:
- 在 C++ 中执行 Python 脚本(定义函数)。
- 调用 Python 中定义的函数
pyfunc(a, b)
。 - 获取返回值并转换为 C++ 类型。
分析你的伪代码
void test()
{// 虚构的解释器对象Interpreter vm;// 导入一个 Python 模块(通过原始字符串定义)Ref module = vm.import(R"**(def pyfunc(a, b):return a + b)**");// 调用 Python 中的 pyfunc 函数Ref resObj = module.call("pyfunc", 1, 2);// 提取 Python 对象为 C++ int 类型int result = extract<int>(resObj);
}
背后理解
1. vm.import(...)
- 表示将一段 Python 脚本动态“导入”或加载为模块。
R"**(...)"
是 C++ 的原始字符串字面量,表示不会转义,适合多行代码。
等价于把 Python 代码:
def pyfunc(a, b):return a + b
注入到解释器中。
2. module.call("pyfunc", 1, 2);
- 动态调用 Python 函数
pyfunc(1, 2)
。 - 返回值是 Python 对象(封装为
Ref
类型,可能是某种智能指针或包装类)。
3. extract<int>(resObj);
- 把 Python 对象转成 C++ 中的
int
类型。 - 相当于你得到了
3
,因为1 + 2 = 3
。
对应的真实 CPython API 示例
你上面的伪代码用的是某个抽象封装(比如 boost::python、pybind11、或自定义解释器)。如果用 原生 CPython API 来做相同的事情,代码类似这样:
#include <Python.h>
void test() {Py_Initialize();const char* code = R"(
def pyfunc(a, b):return a + b
)";PyRun_SimpleString(code);PyObject* main = PyImport_AddModule("__main__");PyObject* global_dict = PyModule_GetDict(main);PyObject* func = PyDict_GetItemString(global_dict, "pyfunc");if (func && PyCallable_Check(func)) {PyObject* args = PyTuple_Pack(2, PyLong_FromLong(1), PyLong_FromLong(2));PyObject* result = PyObject_CallObject(func, args);long c_result = PyLong_AsLong(result);printf("Result: %ld\n", c_result);Py_DECREF(args);Py_DECREF(result);}Py_Finalize();
}
总结理解点
关键词 | 含义 |
---|---|
R"**(...)" | 原始字符串,方便写多行 Python 代码 |
vm.import(...) | 类似于 Python 模块导入,但用于动态注入脚本 |
.call(...) | 调用 Python 函数并返回 Python 对象 |
extract<T> | 把 Python 对象转换为 C++ 类型 |
CPython API | 可以直接用 Py_Initialize , PyRun_SimpleString , PyObject* 调用 |
这段代码展示了 在 C++ 中注册 C++ 函数给 Python 使用,并在 Python 中调用该函数,这是嵌入 Python 的一个高级特性,常用于游戏引擎、嵌入式脚本系统等。下面是详细解释:
代码理解
int cxxfunc(const string& msg) {cout << msg;return 42;
}
这是一个普通的 C++ 函数,接受一个字符串,打印出来,返回 42。
void test()
{Interpreter vm; // 假设你有一个内嵌的 Python 虚拟机对象// 向 Python 注册 C++ 函数vm.builtins.def("cxxfunc", cxxfunc);// 导入/执行 Python 脚本Ref module = vm.import(R"**(
def pyfunc(a, b):cxxfunc("Hello!")return a + b
)**");// 调用 Python 函数Ref resObj = module.call("pyfunc", 1, 2);
}
总结这个过程
步骤 | 描述 |
---|---|
1. 定义 C++ 函数 | int cxxfunc(const string&) ,将来让 Python 调用它。 |
2. 注册到 Python | vm.builtins.def("cxxfunc", cxxfunc); 这一步把 C++ 函数注册为 Python 可用的全局函数。 |
3. 编写 Python 脚本 | Python 调用了 cxxfunc("Hello!") 。 |
4. 调用 Python 函数 | C++ 端用 .call("pyfunc", 1, 2) 执行 pyfunc 。 |
背后机制(类比 pybind11 或 Boost.Python)
你用的 vm.builtins.def(...)
类似于 pybind11 中的:
py::module_::import("__main__").attr("cxxfunc") = py::cpp_function(cxxfunc);
实际效果
运行这段代码时:
- 控制台会打印:
Hello!
- Python 函数
pyfunc(1, 2)
会返回3
,即a + b
。 cxxfunc
被 Python 调用时会输出字符串并返回 42(虽然这个返回值在 Python 中没用到)。
应用场景
这种嵌入式调用方式可用于:
场景 | 示例 |
---|---|
游戏脚本 | Python 调用 playSound("boom.wav") 实际执行 C++ 函数 |
工业控制 | Python 写控制逻辑,但实际操作硬件是底层 C++ |
数据处理 | 用 Python 组织逻辑流程,用 C++ 实现高性能计算 |
结论
你已经实现了:
- 从 C++ 向 Python 注册函数;
- Python 脚本中调用 C++ 函数;
- Python 和 C++ 之间来回传递数据。
这是 C++ 与 Python 脚本系统集成的核心能力。
你这段代码展示了如何在 C++ 中将一个 C++ 类(含成员函数)暴露给 Python 解释器,并让 Python 调用它的成员函数。这是一种高级的 C++ ↔ Python 绑定机制,适合嵌入式脚本、游戏开发、插件系统等场景。
下面逐步解析并翻译这段代码的意义。
逐行分析
struct Thing {void action(int a, int b);
};
定义了一个简单的 C++ 结构体 Thing
,里面有一个成员函数 action
。
void test() {Interpreter vm; // 创建解释器对象
假设 Interpreter
是你封装的 Python 虚拟机对象。
Ref m = vm.builtins;
获取内置模块,用于注册类和函数。
Ref c = m.class_<Thing>("Thing").def("action", &Thing::action);
向 Python 暴露 C++ 的类 Thing
,并绑定其成员函数 action
为 Python 可调用函数。
这段伪代码类似于 PyBind11 中的:
py::class_<Thing>(m, "Thing").def("action", &Thing::action);
Thing t;Ref wrap_t = c.wrapInstance(t);wrap_t.call("action", 1, 2);
}
- 创建一个 C++ 的
Thing
实例。 wrapInstance
把这个实例转换成 Python 端可识别的对象(通常是某种封装指针)。- 通过 Python 的方式调用
action(1, 2)
—— 实际调用的是t.action(1, 2)
。
背后机制
操作 | 作用 |
---|---|
.class_<Thing>("Thing") | 把 C++ 类注册为 Python 类。 |
.def("action", &Thing::action) | 绑定成员函数到 Python。 |
wrapInstance(t) | 把 C++ 实例包成 Python 对象。 |
call("action", ...) | 在 Python 层调用方法(但底层执行 C++ 函数)。 |
示例效果
Python 中表现为:
obj = Thing()
obj.action(1, 2)
这调用的是你写的 C++ Thing::action(1, 2)
。
总结
你这段代码描述了以下概念:
概念 | 描述 |
---|---|
C++ 类暴露给 Python | 允许 Python 实例化 C++ 类,并调用其成员函数 |
Python 调用成员函数 | Python 的 .call(...) 最终会回调到 C++ 成员函数 |
脚本与底层集成 | 非常适用于游戏开发、嵌入式设备等对性能和可扩展性都有要求的项目 |
你这段代码展示了一个 C++ 可变参数模板 + 类型擦除 + 参数打包 + 调用解释器函数的机制,常用于实现 通用的脚本函数调用接口,比如将 C++ 参数传给一个 Python 函数。
逐段理解
1. 基础 unpack 函数(递归终止)
void unpack(vector<Ref>& v) {}
当参数包为空时,递归终止。什么都不做。
2. 参数展开 + 转换 + 收集
template<typename T, typename ...Args>
void unpack(vector<Ref>& v, const T&& a, const Args&&... args) {v.push_back(objectFromT(std::forward<T>(a)));unpack(v, std::forward<Args>(args)...);
}
这段是参数展开递归模板的核心:
步骤 | 描述 |
---|---|
1 | 把当前参数 a 转换成一个 Ref (可能是 Python 对象) |
2 | objectFromT(...) 是类型擦除函数:将任意类型 T 转为统一的 Ref 类型(用于解释器调用) |
3 | 把 Ref 放入 vector<Ref> 容器中 |
4 | 递归处理剩下的参数 |
3. 最终接口:call(...)
template<typename ...Args>
Ref call(const string& name, const Args&&... args) {vector<Ref> argv;unpack(argv, std::forward<Args>(args)...);runCode(lookup(name), argv);
}
这是你提供给用户调用的通用接口:
步骤 | 含义 |
---|---|
name | 要调用的函数名(通常是 Python 脚本中的函数) |
args... | 任意数量的 C++ 参数 |
unpack(...) | 把 C++ 参数全部转换为 Ref 类型并放入 argv 中 |
lookup(name) | 查找解释器中函数的对象(比如 Python 中的 pyfunc ) |
runCode(...) | 用解释器执行函数并传入参数 |
背后思想:类型擦除 + 参数打包
objectFromT(T)
:将int
,string
,double
,Thing*
等全部转换为统一Ref
类型。vector<Ref>
:作为解释器通用参数容器。unpack(...)
:实现递归参数收集。call(...)
:简洁通用的接口隐藏了复杂的参数转换和打包过程。
举个例子
你这样调用:
call("pyfunc", 1, 3.14, "hello", someObject);
实际做了什么:
objectFromT(1)
→Ref(int)
objectFromT(3.14)
→Ref(double)
objectFromT("hello")
→Ref(str)
objectFromT(someObject)
→Ref(object)
- 调用解释器中函数
pyfunc
,传入参数[1, 3.14, "hello", someObject]
总结
你实现了一个 可扩展、类型安全、语法简洁的 C++ 调用解释器函数接口。它支持:
- 任意参数数量(可变参数模板)
- 类型转换封装(
objectFromT
) - 与 Python / Lua / JS 等解释器无缝连接(
Ref
,runCode
,lookup
)
这正是许多嵌入式脚本系统的底层核心机制。
这段代码是一个虚拟机(VM)执行字节码的解释器主循环的简化版,核心思想和 Python 的 CPython 虚拟机非常相似。下面为你逐行解析其含义,并总结设计背后的思想。
你的函数定义
Ref runCode(ByteCode code, vector<Ref> args) {Frame f(args);int pc = 0;
runCode(...)
: 执行解释器中的函数体(字节码)。code
: 表示某个函数或脚本的字节码序列(每 2 字节一个指令 + 参数)。args
: 调用时传入的参数。Frame f(args)
: 新建一个栈帧,保存局部变量、栈等上下文。pc
: 程序计数器(Program Counter),指向当前字节码的偏移量。
主循环:解释执行字节码
while (true) {byte opcode = code[pc];byte param = code[pc + 1];
一次取出一个指令(2 字节),其中:
opcode
:操作码,表示要做什么(如 PUSH、POP、JUMP 等)param
:参数(比如变量索引、跳转地址、参数数量等)
指令解释
switch (opcode) {
你实现了一个字节码解释器的指令集,每种操作码做对应的行为。
PUSH
case PUSH:f.stack.push(f.vars[param]);break;
- 从局部变量数组中取出变量
vars[param]
- 推入运行时栈
stack
POP
case POP:f.vars[param] = f.stack.pop();break;
- 从栈中弹出值
- 存入变量槽
vars[param]
JUMP_TO
case JUMP_TO:pc = param;continue;
- 改变
pc
,跳转到指定位置(param
是偏移量) - 注意
continue
跳过了pc += 2
,不会前进
CALL_FUNCTION
case CALL_FUNCTION:runCode(pop(), popArgs(param));break;
pop()
:从栈中弹出被调用函数(或字节码对象)popArgs(param)
:从栈中弹出param
个参数(调用参数)- 递归调用
runCode(...)
RETURN_VALUE
case RETURN_VALUE:return f.stack.pop();
- 函数结束,返回结果(从栈顶取出)
👣 继续前进
pc += 2;
默认每条指令占 2 字节,所以每轮前进 2 字节。
嵌套调用演示
runCode()
runCode()
runCode()
这说明你支持嵌套函数调用,每次 CALL_FUNCTION
会进入一个新的 Frame
并递归调用 runCode(...)
,这就是解释器的函数调用栈机制。
你实现的核心概念:
概念 | 描述 |
---|---|
字节码虚拟机 | 用程序计数器逐字节解释执行指令 |
栈帧 Frame | 包含局部变量数组 vars 、运行栈 stack 等上下文 |
操作码 opcode | 表示操作类型,例如 PUSH、CALL、RETURN 等 |
参数 param | 当前指令的辅助参数 |
函数调用 | 通过 CALL_FUNCTION 实现函数嵌套和参数传递 |
返回值 | 从当前栈帧返回计算结果 |
总结
你实现的是一个简化的 C++ 字节码解释器运行时核心,具备如下特性:
- 字节码驱动控制流程(如跳转、调用)
- 支持栈式计算模型
- 局部变量访问
- 支持函数调用、返回机制
- 非常类似 Python、Lua 的 VM 设计
代码片段展示了一个简化的 引用计数型对象系统,类似 Python 或 JavaScript 的对象模型。下面是对各个结构和行为的详细中文解释,帮你完全理解这段代码的设计思想和用途。
整体设计目标
你在用类似 Python 的方式构建一个 统一对象类型系统,其中:
- 所有值(int、string、list、dict)都继承自
Object
。 - 所有对象都通过
Ref
来间接引用(类似智能指针)。 - 每个对象通过
m_refcount
管理生命周期(引用计数)。
各部分详细解析
Object
struct Object {int m_refcount;
};
- 所有对象的基类。
- 包含
m_refcount
,用于引用计数,控制对象何时析构。
基本对象类型(派生类)
Str
struct Str : Object {std::string v;
};
- 表示字符串对象。
- 成员
v
是具体的字符串值。
Int
struct Int : Object {int v;
};
- 表示整数对象。
v
是其数值。
List
struct List : Object {std::vector<Ref> v;
};
- 表示列表对象。
- 存储一个
Ref
类型的向量,即引用了其它对象。
Dict
struct Dict : Object {std::map<int, Ref> v;
};
- 表示字典(键值对),这里的键是
int
类型,值是Ref
。 - 可类比 Python 的
dict
。
📎 Ref
:对象引用
struct Ref {Object* m_ptr;
};
Ref
是一个轻量对象引用类型,等价于智能指针。- 指向真实对象(继承自
Object
的任何派生类)。
应该配合引用计数增加/减少使用,例如类似 boost::intrusive_ptr 或手动实现 retain/release。
类型转换与提取
template<typename T>
T extract(Ref ref);
这是一个泛型模板函数,目的是从 Ref
中提取具体类型值。
特化版本(提取 std::string
)
template<>
std::string extract(Ref ref) {return dynamic_cast<Str*>(ref.m_ptr)->v;
}
- 将
ref.m_ptr
强制转换为Str*
- 提取其
v
字段(string 值)
如果传入的不是
Str
类型,dynamic_cast
会返回nullptr
,可能导致 dereference 崩溃,建议做安全检查或使用static_cast
(在你确认类型无误时)。
总结:你实现了什么?
你正在构建一个面向解释器的对象系统基础设施,具有以下特征:
特征 | 说明 |
---|---|
面向对象抽象 | 所有对象都继承自基类 Object |
动态类型系统 | 类型信息通过 dynamic_cast 动态识别 |
引用计数管理 | 通过 m_refcount 管理内存 |
引用封装 | 统一使用 Ref 来间接操作所有对象 |
类型提取机制 | 通过 extract<>() 将 Ref 转换为真实类型值 |
建议改进(可选)
- 管理引用计数:
- 类似
boost::intrusive_ptr<Object>
自动管理m_refcount
- 或定义
retain()
/release()
手动管理
- 类似
- 类型安全性提升:
- 增加类型检查:
if (auto s = dynamic_cast<Str*>(ref.m_ptr)) { ... }
- 或使用
std::variant
/typeid
做类型判断
- 增加类型检查:
- 抽象提取方式:
- 支持更多类型:如
int
、List
、Dict
等 - 或改用
visitor
模式处理对象
如果你继续开发解释器、虚拟机、或动态语言运行时,这样的对象系统是非常常见且实用的设计基础。如果你有后续如调用机制、垃圾回收、
- 支持更多类型:如
相关文章:
CppCon 2014 学习:Lightning Talk: Writing a Python Interpreter for Fun and Profit
Lightning Talk: Writing a Python Interpreter for Fun and Profit 这段内容在讲的是 Python 的执行模型,尤其是 CPython 的工作流程。下面是逐步解析: Python 是动态类型语言(Dynamically typed) 变量类型在运行时决定。x 4…...

CTFHub-RCE 命令注入-过滤运算符
观察源代码 代码里面可以发现过滤了运算符,我们可以尝试分号; 判断是Windows还是Linux 源代码中有 ping -c 4 说明是Linux 查看有哪些文件 127.0.0.1;ls 打开flag文件 cat这个php文件 127.0.0.1;cat flag_257413168915334.php 可是发现 文本内容显示…...

【音视频】H265 NALU分析
1 H265 概述 H264 与 H265 的区别 传输码率:H264 由于算法优化,可以低于 2Mbps 的速度实现标清数字图像传送;H.265 High Profile 可实现低于 1.5Mbps 的传输带宽下,实现 1080p 全高清视频传输。 编码架构:H.265/HEVC…...

运维 vm 虚拟机ip设置
虚拟网络设置 nat 模式 网卡 主机设置网卡地址 虚拟机绑定网卡...

飞牛fnNAS存储模式RAID 5数据恢复
目录 一、添加硬盘 二、创建RAID 5 存储空间 三、上传测试文件 四、拆除硬盘 五、更换硬盘 六、修复RAID 5 七、验证其内文件 八、NAS系统崩溃后的数据盘 前文《飞牛fnNAS存储空间模式详解》 中介绍了fnNAS存储空间的几个模式,细心的网友应该能感受到,我是非常推崇R…...

论文笔记:DreamDiffusion
【初中生也能看得懂的讲解】 想象一下,我们能不能直接用“脑子想”来画画?比如你想到一只猫,电脑就能画出一只猫。这听起来是不是很酷?科学家们一直在努力实现这个“意念画画”的梦想。 以前,科学家们可能会用一种叫…...
户外摄像头监控如何兼顾安全实时监控
一、技术手段提升隐私安全性 硬件与功能设计 采用支持隐私保护技术的设备,例如带电子开关的摄像头(可远程控制摄像头启闭)3,或搭载本地AI算法的设备,仅识别人形、车辆等目标,减少无关信息采集。 使用安全…...
Neo4j 备份与恢复:原理、技术与最佳实践
在数据驱动的应用中,图数据库Neo4j承载着至关重要的关联数据。确保其数据安全与业务连续性依赖于强大的备份与恢复策略。本文将深入探讨Neo4j备份恢复的核心原理、关键技术、实用技巧及行业最佳实践,内容基于官方最新文档。 构建健壮的 Neo4j 备份恢复体…...

简单实现Ajax基础应用
Ajax不是一种技术,而是一个编程概念。HTML 和 CSS 可以组合使用来标记和设置信息样式。JavaScript 可以修改网页以动态显示,并允许用户与新信息进行交互。内置的 XMLHttpRequest 对象用于在网页上执行 Ajax,允许网站将内容加载到屏幕上而无需…...
关于 java:3. Java 常用类库与数据结构
一、String 1.1 String 是什么? public final class String implements java.io.Serializable, Comparable<String>, CharSequence特点: 是 不可变对象(immutable) 是 final 类,不能被继承 内部使用 字符数组…...

数据挖掘顶刊《IEEE Transactions on Knowledge and Data Engineering》2025年5月研究热点都有些什么?
本推文对2025年5月出版的数据挖掘领域国际顶级期刊《IEEE Transactions on Knowledge and Data Engineering》进行了分析,对收录的62篇论文的关键词与研究主题进行了汇总,并对其中的研究热点进行了深入分析,希望能为相关领域的研究人员提供有…...

LabVIEW双光子显微镜开发
基于LabVIEW 开发高性能双光子显微镜系统,聚焦于生物样本深层成像与纳米材料三维表征。实现了超快激光控制、多维数据采集与实时图像重建。系统采用飞秒激光光源与高精度振镜扫描模块,结合 LabVIEW 的 FPGA 实时控制能力,可对活体组织、荧光纳…...

WordPress 6.5版本带来的新功能
WordPress 6.5正式上线了!WordPress团队再一次为我们带来了许多新的改进。在全球开发者的共同努力下,WordPress推出了许多新的功能,本文将对其进行详细总结。 Hostease的虚拟主机现已支持一键安装最新版本的WordPress。对于想要体验WordPres…...
将材质球中的纹理属性对应的贴图保存至本地
通过Texture2D的EncodeToPNG方法将纹理转为图片形式 material.GetTexture方法通过属性名获取纹理贴图 material.SetTexture方法通过属性名设置纹理贴图 属性名可在shader代码中查看 using UnityEngine; using System.IO;public class TextureSaver : MonoBehaviour {public…...
Linux应用开发之网络套接字编程
套接字(Socket)是计算机网络数据通信的基本概念和编程接口,允许不同主机上的进程(运行中的程序)通过网络进行数据交换。它为应用层软件提供了发送和接收数据的能力,使得开发者可以在不用深入了解底层网络细…...

实现RabbitMQ多节点集群搭建
目录 引言 一、环境准备 二、利用虚拟机搭建 三、镜像集群配置 四、HAProxy实现负载均衡(主用虚拟机操作) 五、测试RabbitMQ集群搭建情况 引言 在现代分布式系统中,消息队列(Message Queue)扮演着至关重要的角色,而 RabbitMQ 作为…...

GLIDE论文阅读笔记与DDPM(Diffusion model)的原理推导
Abstract 扩散模型(Diffusion model)最近被证明可以生成高质量的合成图像,尤其是当它们与某种引导技术结合使用时,可以在生成结果的多样性与保真度之间进行权衡。本文探讨了在文本条件图像生成任务中使用扩散模型,并比…...

机器学习——放回抽样
为了构建树集成模型,需要一种叫做有放回采样的技术。 以4个标记为演示,分别是红色、黄色、绿色和蓝色,用一个黑色的袋子把这四个标记的例子放进去,然后从这个袋子里有放回地抽取四次,抽出一个标记,结果是绿…...
前端内存泄漏:原理、检测与防范实践
一、什么是内存泄漏 内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因未能被释放或无法被释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。 在前端开发中,虽然现代浏览器具备垃…...

Go的隐式接口机制
正确使用Interface 不要照使用C/Java等OOP语言中接口的方式去使用interface。 Go的Interface的抽象不仅可以用于dynamic-dispatch 在工程上、它最大的作用是:隔离实现和抽象、实现完全的dependency inversion 以及interface segregation(SOLID principle中的I和D)。…...
UE音频中间件wwise插件
虚幻引擎用wwise插件有什么用? 没有这个插件不是也能播放声音吗? 为什么要用他? 在Unreal Engine(UE)中使用 Wwise 插件,不是因为 UE 不能做声音,而是因为 Wwise 更强、更专业,适合复杂的音频需求。 🎧 …...
C++.cstring string
C.cstring string 1. C 中的字符串概述1.1 C 中字符串的两种表示方式C 中的 cstring示例代码 C 中的 string示例代码 1.2 C 中字符串的使用场景使用 cstring 的场景使用 string 的场景示例对比使用 cstring 的示例使用 string 的示例 2. C 中的 cstring2.1 cstring 的定义与基本…...
Spring AOP 和 AspectJ 有什么区别
1. 织入方式 Spring AOP: 运行时织入:Spring AOP 使用动态代理技术(如 JDK 动态代理或 CGLIB 代理)在运行时创建代理对象。 依赖 Spring 容器:仅支持 Spring 管理的 Bean。 AspectJ: 编译时织入…...

报表/报告组件(二)-实例与实现解释
上篇《报表/报告组件(一)-指标/属性组件设计》介绍了组件核心指标/属性设计,本文以实例介绍各个特性的实现和效果,实例是多个报告融合,显示所有的特性。 设计 指标/属性组件是报告/报表关键部分,上篇已介绍过,本节回顾…...
linux的实时性
Linux 的实时性取决于其内核配置和使用场景。标准 Linux 内核(非实时内核)在设计上更注重吞吐量和公平调度,而非严格的实时性。但通过以下方式可以显著提升其实时性能: 1. 标准 Linux 内核的实时性 优点: 适用于大多数…...
Opencv4 c++ 自用笔记 04 图像滤波与边缘检测
图像滤波与边缘检测 直接采集到的图像可能带有噪声的干扰,因此去除噪声是图像预处理中十分重要的一步。图像滤波是图像噪声去除的重要方式。 图像卷积 卷积操作广泛应用于信号处理领域,而图像本质上可以视为一种二维信号数据。 卷积过程可以理解为一…...

流媒体基础解析:音视频封装格式与传输协议
在视频处理与传输的完整流程中,音视频封装格式和传输协议扮演着至关重要的角色。它们不仅决定了视频文件的存储方式,还影响着视频在网络上的传输效率和播放体验。今天,我们将深入探讨音视频封装格式和传输协议的相关知识。 音视频封装格式 什…...

一个html实现数据库自定义查询
使用场景 应用上线后甲方频繁的找开发查询数据库数据,且没有固定的查询规律,产品经理也没有规划报表需求。 实现方案 后端开放自定义sql查询,屏蔽所有数据库的高危操作,将常用查询的sql放在一个html中的js中直接查询࿰…...
OCC笔记:TopoDS_Edge上是否一定存在Geom_Curve
1. 问题 写occt代码时,访问边的几何数据,通常有以下代码,若边不为空,BRep_Tool::Curve函数是否能返回Curve的有效对象指针呢? //其他略...const TopoDS_Edge& curEdge TopoDS::Edge(edgeExp.Current()); if( cu…...
Python aiohttp 全面指南:异步HTTP客户端/服务器框架
边写代码零食不停口 盼盼麦香鸡味块 、卡乐比(Calbee)薯条三兄弟 独立小包、好时kisses多口味巧克力糖、老金磨方【黑金系列】黑芝麻丸 边写代码边贴面膜 事业美丽两不误 DR. YS 野森博士【AOUFSE/澳芙雪特证】377专研美白淡斑面膜组合 优惠劵 别光顾写…...