160 lines
8.4 KiB
HTML
160 lines
8.4 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>为什么选择 Python - Future OSS 文档</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||
<link rel="stylesheet" href="../css/main.css" />
|
||
<link rel="stylesheet" href="../css/dock.css" />
|
||
<link rel="stylesheet" href="../css/docs.css" />
|
||
</head>
|
||
<body>
|
||
<canvas id="particles"></canvas>
|
||
<div id="dock-container"></div>
|
||
|
||
<main class="page-docs">
|
||
<header class="docs-header">
|
||
<button class="docs-hamburger" id="docs-hamburger" aria-label="切换导航菜单">
|
||
<span class="docs-hamburger-line"></span>
|
||
<span class="docs-hamburger-line"></span>
|
||
<span class="docs-hamburger-line"></span>
|
||
</button>
|
||
<div class="docs-header-title">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" width="22" height="22">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/>
|
||
</svg>
|
||
<span>文档中心</span>
|
||
</div>
|
||
<div class="docs-header-breadcrumb">入门 · 为什么用Python</div>
|
||
<div class="docs-header-actions">
|
||
<a href="https://gitee.com/starlight-apk/feature-oss/wikis" target="_blank" class="docs-wiki-link">完整 Wiki</a>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="docs-sidebar-overlay" id="docs-overlay"></div>
|
||
|
||
<div class="docs-layout">
|
||
<aside class="docs-sidebar" id="docs-sidebar">
|
||
<div class="docs-nav-section">
|
||
<div class="docs-nav-section-title">入门</div>
|
||
<a href="index.html" class="docs-nav-item">什么是 FutureOSS<span class="nav-path">/ 项目介绍</span></a>
|
||
<a href="why-python.html" class="docs-nav-item active">为什么选择 Python<span class="nav-path">/ 技术选型</span></a>
|
||
<a href="architecture.html" class="docs-nav-item">架构设计<span class="nav-path">/ 三层架构</span></a>
|
||
</div>
|
||
<div class="docs-nav-section">
|
||
<div class="docs-nav-section-title">快速开始</div>
|
||
</div>
|
||
<div class="docs-nav-section">
|
||
<div class="docs-nav-section-title">插件</div>
|
||
<a href="plugins.html" class="docs-nav-item">官方插件列表<span class="nav-path">/ 12+ 插件</span></a>
|
||
<a href="development.html" class="docs-nav-item">插件开发指南<span class="nav-path">/ 开发基础</span></a>
|
||
</div>
|
||
</aside>
|
||
|
||
<div class="docs-content-wrapper">
|
||
<article class="docs-content">
|
||
<h1>🐍 为什么从 Go 重构为 Python?</h1>
|
||
|
||
<p>Go 的 <code>plugin</code> 包不适合热插拔场景。<code>.so</code> 文件与主程序是独立编译单元,类型不共享,依赖注入后接口不匹配会导致 <code>panic</code>。Python 的动态特性天然适合插件化架构。</p>
|
||
|
||
<h2>技术对比</h2>
|
||
<table>
|
||
<thead>
|
||
<tr><th>问题</th><th>Go 方案</th><th>Python 方案</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td>插件热插拔</td><td><code>plugin.Open(".so")</code></td><td><code>importlib</code> 动态加载 <code>.py</code></td></tr>
|
||
<tr><td>依赖注入</td><td>反射注入,类型不匹配 → panic</td><td>直接传 dict/对象,无编译隔离</td></tr>
|
||
<tr><td>开发效率</td><td>每次改插件需重新编译</td><td>改完即生效,零编译</td></tr>
|
||
<tr><td>配置类型</td><td><code>map[string]string</code> 限制</td><td><code>dict[str, Any]</code> 原生支持任意类型</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h2>Go 插件系统的致命问题</h2>
|
||
<p>Go 的插件机制依赖 <code>plugin.Open()</code> 加载编译好的 <code>.so</code> 文件。每个 <code>.so</code> 是独立的编译单元,无法共享类型定义。这意味着插件中定义的接口与框架中的接口即使签名相同,也被视为不同类型,导致依赖注入后接口为 <code>nil</code>,运行时直接 <code>panic</code>。</p>
|
||
|
||
<h2>Python 的优势</h2>
|
||
<ul>
|
||
<li><strong>动态类型</strong> — 没有编译时类型检查,插件直接使用框架定义的类型</li>
|
||
<li><strong>importlib</strong> — 运行时动态加载 <code>.py</code> 文件,零编译开销</li>
|
||
<li><strong>类型共享</strong> — 插件通过 <code>from oss.plugin.types import Plugin</code> 直接引用框架类型</li>
|
||
<li><strong>开发迭代快</strong> — 改完代码即生效,无需重新编译</li>
|
||
</ul>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<a href="https://gitee.com/starlight-apk/feature-oss/wikis" target="_blank" class="docs-wiki-btn">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/>
|
||
</svg>
|
||
<span>获取更多信息</span>
|
||
</a>
|
||
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
|
||
<script src="../js/dock.js"></script>
|
||
<script src="../js/particles.js"></script>
|
||
<script src="../js/parallax.js"></script>
|
||
<script src="../js/animations.js"></script>
|
||
<script>
|
||
// 汉堡菜单交互逻辑
|
||
(function() {
|
||
const hamburger = document.getElementById('docs-hamburger');
|
||
const sidebar = document.getElementById('docs-sidebar');
|
||
const overlay = document.getElementById('docs-overlay');
|
||
|
||
if (!hamburger || !sidebar || !overlay) return;
|
||
|
||
function openSidebar() {
|
||
sidebar.classList.add('is-open');
|
||
overlay.classList.add('is-visible');
|
||
hamburger.classList.add('is-active');
|
||
document.body.style.overflow = 'hidden';
|
||
}
|
||
|
||
function closeSidebar() {
|
||
sidebar.classList.remove('is-open');
|
||
overlay.classList.remove('is-visible');
|
||
hamburger.classList.remove('is-active');
|
||
document.body.style.overflow = ''';
|
||
}
|
||
|
||
function toggleSidebar() {
|
||
if (sidebar.classList.contains('is-open')) {
|
||
closeSidebar();
|
||
} else {
|
||
openSidebar();
|
||
}
|
||
}
|
||
|
||
hamburger.addEventListener('click', toggleSidebar);
|
||
overlay.addEventListener('click', closeSidebar);
|
||
|
||
sidebar.querySelectorAll('.docs-nav-item).forEach(link => {
|
||
link.addEventListener('click', closeSidebar);
|
||
});
|
||
|
||
document.addEventListener('keydown', (e) => {
|
||
if (e.key === 'Escape' && sidebar.classList.contains('is-open')) {
|
||
closeSidebar();
|
||
}
|
||
});
|
||
|
||
let resizeTimer;
|
||
window.addEventListener('resize', () => {
|
||
clearTimeout(resizeTimer);
|
||
resizeTimer = setTimeout(() => {
|
||
if (window.innerWidth > 768 && sidebar.classList.contains('is-open')) {
|
||
closeSidebar();
|
||
}
|
||
}, 100);
|
||
});
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|