Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .translate/state/need_for_speed.md.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
source-sha: cc9c3256dc35bd277cb25d0089f0a0452c0fa94e
synced-at: "2026-03-20"
source-sha: 21f1ea0669031ccc0ee0194878439a87de5d248d
synced-at: "2026-04-10"
model: claude-sonnet-4-6
mode: NEW
mode: UPDATE
section-count: 5
tool-version: 0.13.1
tool-version: 0.14.1
6 changes: 3 additions & 3 deletions .translate/state/numba.md.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
source-sha: ab53ebc3d56705b836f0ca8207d70d1ff3ba0936
synced-at: "2026-04-08"
source-sha: 21f1ea0669031ccc0ee0194878439a87de5d248d
synced-at: "2026-04-10"
model: claude-sonnet-4-6
mode: UPDATE
section-count: 7
tool-version: 0.13.1
tool-version: 0.14.1
105 changes: 32 additions & 73 deletions lectures/need_for_speed.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ translation:

## 概述

可以说,Python 是科学计算领域最流行的编程语言
Python 是科学计算许多方面最流行的编程语言

这得益于以下几点:

Expand Down Expand Up @@ -102,35 +102,36 @@ mpl.rcParams['font.family'] = ['Source Han Serif SC'] # i18n
import random
```


## 主要科学库

让我们简要回顾一下 Python 的科学库。


### 为什么需要它们?

我们使用科学库的一个原因是它们实现了我们想要使用的程序。
我们需要 Python 科学库有两个原因:

* 数值积分、插值、线性代数、求根等。
1. Python 体量小
2. Python 速度慢

例如,使用现有的求根程序通常比从头编写一个新程序更好。
**Python 体量小**

(对于标准算法,如果社区能够统一使用一套由专家编写、并经用户调优以尽可能快速和健壮的共同实现,效率将达到最高!)
核心 Python 在设计上体量较小——这有助于优化、易用性和维护。

但这并不是我们使用 Python 科学库的唯一原因。
科学库提供了我们不想——也可能不应该——自己编写的程序:

另一个原因是纯 Python 速度不够快
* 数值积分、插值、线性代数、求根等

因此,我们需要那些专门用于加速 Python 代码执行的库。
**Python 速度慢**

它们通过两种策略来实现这一目标:
我们需要科学库的另一个原因是纯 Python 的速度相对较慢。

1. 使用编译器将类 Python 语句转换为针对单一逻辑线程的快速机器码,以及
2. 在多个"工作单元"(例如 CPU、GPU 内部的各个线程)之间并行化任务。
科学库通过三种主要策略来加速执行:

我们将在本讲座及本系列剩余讲座中广泛讨论这些思想。
1. 向量化:提供已编译的机器码以及使该代码可访问的接口
1. JIT 编译:在运行时将类 Python 语句转换为快速机器码的编译器
2. 并行化:将任务分配到多个线程 / CPU / GPU / TPU
Comment on lines +131 to +132

我们将在下文深入讨论这些思想。

### Python 的科学生态系统

Expand All @@ -152,8 +153,7 @@ import random
* Pandas 提供用于操作数据的类型和函数。
* Numba 提供一个即时编译器,与 NumPy 配合良好,有助于加速 Python 代码。

我们将在本系列讲座中广泛讨论所有这些库。

我们将在本系列讲座中详细讨论所有这些库。

## 纯 Python 速度慢

Expand All @@ -163,7 +163,6 @@ import random

对于这个主题,如果我们理解是什么导致了执行速度慢,将会很有帮助。


### 高级语言与低级语言

像 Python 这样的高级语言是为人类优化的。
Expand All @@ -180,12 +179,10 @@ import random

另一方面,Python 的标准实现(称为 CPython)无法与 C 或 Fortran 等编译语言的速度相媲美。


### 瓶颈在哪里?

为什么会这样呢?


#### 动态类型

```{index} single: Dynamic Typing
Expand Down Expand Up @@ -216,14 +213,11 @@ a, b = ['foo'], ['bar']
a + b
```

(我们说运算符 `+` 是*重载的*——它的动作取决于它所作用的对象的类型。)

因此,在执行 `a + b` 时,Python 必须首先检查对象的类型,然后调用正确的操作。

这涉及到不可忽视的开销。

如果我们在一个紧密的循环中反复执行此表达式,这种不可忽视的开销就会变成巨大的开销。
这涉及到额外的开销。

如果我们在一个紧密的循环中反复执行此表达式,这种开销就会变得很大。

#### 静态类型

Expand Down Expand Up @@ -258,7 +252,6 @@ int main(void) {

无需类型检查,因此没有额外开销。


### 数据访问

高级语言速度慢的另一个原因是数据访问。
Expand All @@ -267,22 +260,15 @@ int main(void) {

#### 使用编译代码求和

在 C 或 Fortran 中,这些整数通常存储在数组中,数组是一种用于存储同类数据的简单数据结构。

这样的数组存储在单个连续的内存块中:
在 C 或 Fortran 中,整数数组存储在单个连续的内存块中:

* 在现代计算机中,内存地址分配给每个字节(1字节 = 8位)。
* 例如,一个 64 位整数存储在 8 字节的内存中。
* $n$ 个这样的整数组成的数组占据 $8n$ 个*连续*的内存槽。

此外,编译器通过程序员的声明得知数据类型。

* 在本例中为 64 位整数。
此外,数据类型在编译时是已知的。

因此,每个连续的数据点都可以通过在内存空间中向前移动一个已知且固定的量来访问。

* 在本例中为 8 字节。

#### 在纯 Python 中求和

Python 在一定程度上试图复制这些思想。
Expand All @@ -293,11 +279,7 @@ Python 在一定程度上试图复制这些思想。

因此,访问数据值本身仍然存在开销。

这对速度是一个相当大的拖累。

事实上,内存流量通常是导致执行缓慢的主要因素。


这种开销是导致执行缓慢的主要因素。

### 总结

Expand All @@ -315,11 +297,6 @@ Python 在一定程度上试图复制这些思想。

这个任务最好留给专门的编译器!

某些 Python 库在并行化科学代码方面具有出色的能力——我们将在后续内容中进一步讨论。




## 加速 Python

在本节中,我们将介绍三种加速 Python 代码的相关技术。
Expand All @@ -328,8 +305,6 @@ Python 在一定程度上试图复制这些思想。

稍后我们将研究具体的库以及它们如何实现这些思想。



### {index}`向量化 <single: Vectorization>`

```{index} single: Python; Vectorization
Expand Down Expand Up @@ -360,7 +335,7 @@ Python 在一定程度上试图复制这些思想。
```{figure} /_static/lecture_specific/need_for_speed/matlab.png
```


NumPy 使用类似的模型,灵感来自 MATLAB。

### 向量化 vs 纯 Python 循环

Expand Down Expand Up @@ -418,50 +393,39 @@ with qe.Timer():

在本系列后续讲座中,我们将学习现代 Python 库如何利用即时编译器生成快速、高效、并行化的机器码。




## 并行化

近年来,CPU 时钟速度(即单条逻辑链的运行速度)的增长已大幅放缓。

芯片设计师和计算机程序员通过寻求一条不同的路径来应对这一放缓:并行化。

硬件制造商增加了每台机器中嵌入的核心数量(物理 CPU)。

对于程序员来说,挑战在于通过同时运行多个进程(即并行)来充分利用这些多个 CPU。
这涉及到:

这在科学编程中尤为重要,因为科学编程需要处理:
1. 增加每台机器中嵌入的 CPU 数量
1. 连接 GPU 和 TPU 等硬件加速器

* 大量数据,以及
* CPU 密集型的模拟和其他计算。
对于程序员来说,挑战在于利用这些硬件并行运行多个进程。

下面我们讨论科学计算中的并行化,重点关注:

1. Python 中最佳的并行化工具,以及
1. Python 中的并行化工具,以及
1. 这些工具如何应用于定量经济学问题。


### CPU 上的并行化

让我们回顾一下科学计算中常用的两种主要 CPU 并行化方式,并讨论它们的优缺点。


#### 多进程

多进程是指使用多个处理器并发执行多个进程。

在这个语境中,**进程**是一系列指令(即一个程序)。
多进程是指使用多个处理器并发执行多条逻辑线程。

多进程可以在一台拥有多个 CPU 的机器上进行,也可以在通过网络连接的多台机器上进行
多进程可以在一台拥有多个 CPU 的机器上进行,也可以在通过网络连接的机器集群上进行

在后一种情况下,这些机器的集合通常称为**集群**。

在多进程中,每个进程都有自己的内存空间,尽管物理内存芯片可能是共享的。
在多进程中,*每个进程都有自己的内存空间*,尽管物理内存芯片可能是共享的。

#### 多线程

多线程与多进程类似,不同之处在于,在执行期间,所有线程共享同一内存空间
多线程与多进程类似,不同之处在于,在执行期间,所有线程 *共享同一内存空间*

由于一些[遗留的设计特性](https://wiki.python.org/moin/GlobalInterpreterLock),原生 Python 难以实现多线程。

Expand All @@ -479,7 +443,6 @@ with qe.Timer():

对于我们在这些讲座中所做的绝大多数工作,多线程就足够了。


### 硬件加速器

虽然拥有多核的 CPU 已成为并行计算的标准,但随着专用硬件加速器的兴起,发生了更为深刻的变化。
Expand All @@ -505,7 +468,6 @@ TPU 是较新的发展,由 Google 专门为机器学习工作负载设计。

与 GPU 一样,TPU 擅长并行执行大量矩阵运算。


#### 为何 TPU/GPU 至关重要

使用硬件加速器带来的性能提升可能是惊人的。
Expand All @@ -516,7 +478,6 @@ TPU 是较新的发展,由 Google 专门为机器学习工作负载设计。

这对科学计算尤为重要,因为许多算法天然地映射到 GPU 的并行架构上。


### 单 GPU 与 GPU 服务器

访问 GPU 资源有两种常见方式:
Expand All @@ -531,7 +492,6 @@ TPU 是较新的发展,由 Google 专门为机器学习工作负载设计。

现代 Python 库(如本系列讲座中广泛讨论的 JAX)可以以最少的代码改动自动检测并使用可用的 GPU。


#### 多 GPU 服务器

对于规模更大的问题,包含多个 GPU(通常每台服务器 4-8 个 GPU)的服务器越来越普遍。
Expand All @@ -545,11 +505,10 @@ TPU 是较新的发展,由 Google 专门为机器学习工作负载设计。

这使研究人员能够处理在单个 GPU 或 CPU 上不可行的问题。


### 总结

GPU 计算正变得越来越容易获取,尤其是在 Python 中。

一些 Python 科学库(如 JAX)现在支持 GPU 加速,对现有代码的改动极少。

我们将在后续讲座中更详细地探讨 GPU 计算,并将其应用于一系列经济学应用。
我们将在后续讲座中更详细地探讨 GPU 计算,并将其应用于一系列经济学应用。
Loading
Loading