finish 2025-11-21 ppt
This commit is contained in:
87
2025-11-21/bibliography.bib
Normal file
87
2025-11-21/bibliography.bib
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
@misc{moritz2018raydistributedframeworkemerging,
|
||||||
|
title = {Ray: A Distributed Framework for Emerging AI Applications},
|
||||||
|
author = {Philipp Moritz and Robert Nishihara and Stephanie Wang and Alexey
|
||||||
|
Tumanov and Richard Liaw and Eric Liang and Melih Elibol and Zongheng
|
||||||
|
Yang and William Paul and Michael I. Jordan and Ion Stoica},
|
||||||
|
year = {2018},
|
||||||
|
eprint = {1712.05889},
|
||||||
|
archivePrefix = {arXiv},
|
||||||
|
primaryClass = {cs.DC},
|
||||||
|
url = {https://arxiv.org/abs/1712.05889},
|
||||||
|
}
|
||||||
|
|
||||||
|
@inproceedings{Ma2023,
|
||||||
|
author = {Junming Ma and Yancheng Zheng and Jun Feng and Derun Zhao and Haoqi
|
||||||
|
Wu and Wenjing Fang and Jin Tan and Chaofan Yu and Benyu Zhang and
|
||||||
|
Lei Wang},
|
||||||
|
title = {{SecretFlow-SPU}: A Performant and {User-Friendly} Framework for {
|
||||||
|
Privacy-Preserving} Machine Learning},
|
||||||
|
booktitle = {2023 USENIX Annual Technical Conference (USENIX ATC 23)},
|
||||||
|
year = {2023},
|
||||||
|
isbn = {978-1-939133-35-9},
|
||||||
|
address = {Boston, MA},
|
||||||
|
pages = {17--33},
|
||||||
|
url = {https://www.usenix.org/conference/atc23/presentation/ma},
|
||||||
|
publisher = {USENIX Association},
|
||||||
|
month = jul,
|
||||||
|
}
|
||||||
|
|
||||||
|
@inproceedings{mp-spdz,
|
||||||
|
author = {Marcel Keller},
|
||||||
|
title = {{MP-SPDZ}: A Versatile Framework for Multi-Party Computation},
|
||||||
|
booktitle = {Proceedings of the 2020 ACM SIGSAC Conference on Computer and
|
||||||
|
Communications Security},
|
||||||
|
year = {2020},
|
||||||
|
doi = {10.1145/3372297.3417872},
|
||||||
|
url = {https://doi.org/10.1145/3372297.3417872},
|
||||||
|
}
|
||||||
|
|
||||||
|
@inproceedings{Dam2009,
|
||||||
|
author = "Damg{\aa}rd, Ivan and Geisler, Martin and Kr{\o}igaard, Mikkel and
|
||||||
|
Nielsen, Jesper Buus",
|
||||||
|
editor = "Jarecki, Stanis{\l}aw and Tsudik, Gene",
|
||||||
|
title = "Asynchronous Multiparty Computation: Theory and Implementation",
|
||||||
|
booktitle = "Public Key Cryptography -- PKC 2009",
|
||||||
|
year = "2009",
|
||||||
|
publisher = "Springer Berlin Heidelberg",
|
||||||
|
address = "Berlin, Heidelberg",
|
||||||
|
pages = "160--179",
|
||||||
|
abstract = "We propose an asynchronous protocol for general multiparty
|
||||||
|
computation. The protocol has perfect security and communication
|
||||||
|
complexity {\$}{\backslash}mathcal{\{}O{\}}(n^2|C|k){\$}, where n
|
||||||
|
is the number of parties, |C| is the size of the arithmetic circuit
|
||||||
|
being computed, and k is the size of elements in the underlying
|
||||||
|
field. The protocol guarantees termination if the adversary allows
|
||||||
|
a preprocessing phase to terminate, in which no information is
|
||||||
|
released. The communication complexity of this protocol is the same
|
||||||
|
as that of a passively secure solution up to a constant factor. It
|
||||||
|
is secure against an adaptive and active adversary corrupting less
|
||||||
|
than n/3 players. We also present a software framework for
|
||||||
|
implementation of asynchronous protocols called VIFF (Virtual Ideal
|
||||||
|
Functionality Framework), which allows automatic parallelization of
|
||||||
|
primitive operations such as secure multiplications, without having
|
||||||
|
to resort to complicated multithreading. Benchmarking of a VIFF
|
||||||
|
implementation of our protocol confirms that it is applicable to
|
||||||
|
practical non-trivial secure computations.",
|
||||||
|
isbn = "978-3-642-00468-1",
|
||||||
|
}
|
||||||
|
|
||||||
|
@misc{hbMPC,
|
||||||
|
author = {Donghang Lu and Thomas Yurek and Samarth Kulshreshtha and Rahul
|
||||||
|
Govind and Rahul Mahadev and Aniket Kate and Andrew Miller},
|
||||||
|
title = {{HoneyBadgerMPC} and {AsynchroMix}: Practical {AsynchronousMPC} and
|
||||||
|
its Application to Anonymous Communication},
|
||||||
|
howpublished = {Cryptology {ePrint} Archive, Paper 2019/883},
|
||||||
|
year = {2019},
|
||||||
|
url = {https://eprint.iacr.org/2019/883},
|
||||||
|
}
|
||||||
|
|
||||||
|
@misc{Dumbo-MPC,
|
||||||
|
author = {Yuan Su and Yuan Lu and Jiliang Li and Yuyi Wang and Chengyi Dong
|
||||||
|
and Qiang Tang},
|
||||||
|
title = {Dumbo-{MPC}: Efficient Fully Asynchronous {MPC} with Optimal
|
||||||
|
Resilience},
|
||||||
|
howpublished = {Cryptology {ePrint} Archive, Paper 2024/1705},
|
||||||
|
year = {2024},
|
||||||
|
url = {https://eprint.iacr.org/2024/1705},
|
||||||
|
}
|
||||||
18468
2025-11-21/main.pdf
Normal file
18468
2025-11-21/main.pdf
Normal file
File diff suppressed because it is too large
Load Diff
508
2025-11-21/main.typ
Normal file
508
2025-11-21/main.typ
Normal file
@@ -0,0 +1,508 @@
|
|||||||
|
#import "@preview/typslides:1.3.0": *
|
||||||
|
#import "@preview/codly:1.3.0": *
|
||||||
|
#import "@preview/codly-languages:0.1.1": *
|
||||||
|
#import "slides_component/figures.typ": *
|
||||||
|
#show: codly-init.with()
|
||||||
|
#codly(languages: codly-languages)
|
||||||
|
#show raw: set text(font: ("0xProto Nerd Font", "WenQuanYi Micro Hei"))
|
||||||
|
|
||||||
|
// Project configuration
|
||||||
|
#show: typslides.with(
|
||||||
|
ratio: "16-9",
|
||||||
|
theme: "yelly",
|
||||||
|
font: ("0xProto Nerd Font","WenQuanYi Micro Hei"),
|
||||||
|
font-size: 20pt,
|
||||||
|
link-style: "color",
|
||||||
|
show-progress: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
// The front slide is the first slide of your presentation
|
||||||
|
#front-slide(
|
||||||
|
title: "MPC的通信架构设计思路",
|
||||||
|
authors: "梁俊勇",
|
||||||
|
info: [2025-11-21],
|
||||||
|
)
|
||||||
|
|
||||||
|
// Custom outline
|
||||||
|
#table-of-contents()
|
||||||
|
|
||||||
|
#title-slide()[
|
||||||
|
MPC通信常见问题
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide[
|
||||||
|
在底层通信里,我们常常会遇到这样的场景: \
|
||||||
|
一段代码需要重复调用send()或者recv()方法 \
|
||||||
|
但是这里有较大的性能问题
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "场景1: 一方向另一方发送多个数据")[
|
||||||
|
```python
|
||||||
|
# 发送方
|
||||||
|
for item in items:
|
||||||
|
socket_to_peer.send(item)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 接收方
|
||||||
|
for i in len(items):
|
||||||
|
items[i] = socket_to_peer.recv()
|
||||||
|
```
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "场景2: 一方向多方发送数据")[
|
||||||
|
```python
|
||||||
|
# 发送方
|
||||||
|
for peer in peers:
|
||||||
|
socket_to_peer.send(data)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 接收方
|
||||||
|
for peer in peers:
|
||||||
|
data = socket_to_peer.recv()
|
||||||
|
```
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "问题1: 通信中的数据依赖问题")[
|
||||||
|
这其中的问题在于,每次发送与接受,都会存在数据的依赖关系。具体表现为:
|
||||||
|
- 阻塞式操作: 同步编程中,`send()` 和 `recv()` 是阻塞的,程序会暂停执行,直到当前通信操作完全完成。
|
||||||
|
- 严格串行: 在循环中,后一次的通信操作(无论是发送还是接收)必须等待前一次操作彻底完成后才能启动。
|
||||||
|
- 性能瓶颈: 这种强制性的顺序等待,极大地限制了通信效率,尤其是在需要与多个参与方进行大量数据交换的场景下,导致系统无法充分利用并行处理能力和网络带宽。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "以场景2为例")[
|
||||||
|
```python
|
||||||
|
# 手动展开发送方循环代码
|
||||||
|
# peers = [alice, bob, carol]
|
||||||
|
# for peer in peers:
|
||||||
|
# socket_to_peer.send(data)
|
||||||
|
|
||||||
|
socket_to_alice.send(data)
|
||||||
|
socket_to_bob.send(data) # 在alice没有确认收到数据前,此行代码不会执行
|
||||||
|
socket_to_carol.send(data) # 在bob没有确认收到数据前,此行代码不会执行
|
||||||
|
```
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "以场景2为例")[
|
||||||
|
```python
|
||||||
|
# 手动展开接收方循环代码
|
||||||
|
# peers = [alice, bob, carol]
|
||||||
|
# for peer in peers:
|
||||||
|
# socket_to_peer.recv(data)
|
||||||
|
|
||||||
|
socket_to_alice.recv(data)
|
||||||
|
socket_to_bob.recv(data) # 在没有接收到alice数据前,此行代码不会执行
|
||||||
|
socket_to_carol.recv(data) # 在没有接收到bob数据前,此行代码不会执行
|
||||||
|
```
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "流程图表示")[
|
||||||
|
#align(center)[#show: serial_timeline()]
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "问题2: 传统通信协议的瓶颈")[
|
||||||
|
我们常用的 `TCP` 和 `HTTP/1.1` 协议虽然可靠,但在大规模、高并发的MPC场景下会遇到显著的性能瓶颈:
|
||||||
|
|
||||||
|
- 连接开销大:
|
||||||
|
- TCP三次握手: 每次新建连接都需握手,带来固有延迟。
|
||||||
|
- TCP慢启动: 连接初期传输速度受限,短连接无法有效利用带宽。
|
||||||
|
|
||||||
|
- 协议效率低:
|
||||||
|
- HTTP/1.1队头阻塞: 单个慢请求会阻塞同一连接上的后续所有请求。
|
||||||
|
- 冗余的报文头: HTTP头部是文本格式,存在大量冗余信息。
|
||||||
|
|
||||||
|
- 数据传输未经优化:
|
||||||
|
- 默认无压缩: 协议本身不强制压缩数据,增大了网络负载。
|
||||||
|
- 序列化开销: 使用JSON等文本格式比二进制格式体积更大,处理速度更慢。
|
||||||
|
]
|
||||||
|
|
||||||
|
#title-slide[
|
||||||
|
预备知识
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide()[
|
||||||
|
在我们讲解后续思路与方案之前,我们先来了解一下异步编程。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "异步编程")[
|
||||||
|
异步编程是实现并发的一种主要方式。
|
||||||
|
|
||||||
|
我们可以用在餐厅点餐的例子来理解:
|
||||||
|
|
||||||
|
- 同步(等待的方式):
|
||||||
|
你在柜台点完餐,然后就站在那里一直等到餐做好。中间什么也做不了。
|
||||||
|
|
||||||
|
- 异步(不等待的方式):
|
||||||
|
你在柜台点完餐,服务员给你一个震动的取餐器。你可以回到座位上玩手机、聊天。当取餐器震动时,你再去取餐。
|
||||||
|
|
||||||
|
在程序中:
|
||||||
|
- “点餐”就是发起一个网络请求。
|
||||||
|
- “取餐器”就是一种通知机制。
|
||||||
|
- “玩手机”就是程序在等待期间可以去执行的其他代码。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "并发与异步的关系")[
|
||||||
|
简单来说,它们是“目标”与“手段”的关系。
|
||||||
|
|
||||||
|
- 并发是我们的目标:
|
||||||
|
- 我们希望程序能同时处理多个任务,提高效率。
|
||||||
|
|
||||||
|
- 异步编程是达成目标的手段之一:
|
||||||
|
- 它是我们编写并发程序的一种具体方法。
|
||||||
|
|
||||||
|
好比我们的目标是“同时做好一顿饭(炒菜、煮饭、煲汤)”。
|
||||||
|
|
||||||
|
- 多线程方案:
|
||||||
|
- 请三个厨师,每人负责一项。速度快,但“雇佣成本”高,且需要协调。
|
||||||
|
|
||||||
|
- 异步方案:
|
||||||
|
- 一位经验丰富的厨师,他先按下电饭煲和汤煲的开关(发起异步操作),然后在等待的间隙去炒菜。通过合理安排,一个人高效地完成了所有事情。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "为什么不选择多线程方案")[
|
||||||
|
尽管多线程也能实现并发,但在网络编程中,它常常带来一些挑战:
|
||||||
|
|
||||||
|
- 数据竞争与复杂性:
|
||||||
|
- 当多个线程同时尝试修改同一份数据时,很容易出现混乱,导致程序出错。
|
||||||
|
- 就像多个人同时在同一块白板上写字,最终结果可能一团糟。
|
||||||
|
- 为了避免这种混乱,程序员需要使用复杂的“锁”机制来协调,这非常容易出错,并且难以调试。
|
||||||
|
|
||||||
|
- 特定语言的限制:
|
||||||
|
- 像Python这样的语言,由于其内部机制(全局解释器锁GIL),即使使用多线程,也无法真正同时运行多个计算任务,这限制了其在CPU密集型场景的性能。
|
||||||
|
- 即使是C/C++这类语言,虽然没有GIL,但手动管理线程间的同步和数据安全,也是一个巨大的挑战。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "为什么不选择多线程方案")[
|
||||||
|
- 逻辑直观性:
|
||||||
|
- 即使是像Rust这样能保证线程安全的语言,多线程的逻辑也可能不如异步编程模型(特别是async/await)那样直观和易于理解,尤其是在处理大量网络I/O时。
|
||||||
|
|
||||||
|
因此,在许多网络设计场景中,异步编程往往是更简洁、高效且易于维护的选择。
|
||||||
|
]
|
||||||
|
|
||||||
|
#title-slide[
|
||||||
|
通过有向无环图(DAG)实现通信批次化
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide()[
|
||||||
|
我们可以将数据依赖转换成图问题,进而使用拓扑排序来批次化无依赖关系的数据。\
|
||||||
|
例如刚刚的循环发送。我们可以创建一个缓冲区,将数据先填充至缓冲区,然后在一轮循环结束的时候,统一发送。\
|
||||||
|
接收方同理,创建缓冲区,通过循环解包出对应的数据。\
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "手动批次化示例")[
|
||||||
|
```python
|
||||||
|
# 手动批次化发送方代码
|
||||||
|
# items = [item1, item2, item3]
|
||||||
|
# for item in items:
|
||||||
|
# socket_to_peer.send(item)
|
||||||
|
|
||||||
|
buffer = []
|
||||||
|
for item in items:
|
||||||
|
buffer.append(item)
|
||||||
|
socket_to_peer.send(buffer)
|
||||||
|
```
|
||||||
|
]
|
||||||
|
#slide(title: "批量化流程图表示")[
|
||||||
|
#align(center)[#show: batched_timeline()]
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide()[
|
||||||
|
然后是并发化,如果多个步骤可以并行进行,那么拓扑排序也可以将这些步骤一起发送处理。\
|
||||||
|
例如刚刚的发送给多个参与方的模式。我们便可使用一次并发,在等待确认的时候,发送其他数据。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "并发化示例")[
|
||||||
|
```python
|
||||||
|
# peers = [socket_to_alice, socket_to_bob, socket_to_carol]
|
||||||
|
|
||||||
|
# 创建一组并发的发送任务
|
||||||
|
tasks = [
|
||||||
|
socket_to_peer.send(data) for peer in peers
|
||||||
|
]
|
||||||
|
|
||||||
|
# 同时执行所有发送任务
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
```
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "并发流程图表示")[
|
||||||
|
#align(center)[#show: async_timeline()]
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "动态DAG方案")[
|
||||||
|
主流的动态DAG框架是阿里的隐语框架 @Ma2023。
|
||||||
|
#align(center)[#image("./pics/secretflow.png")]
|
||||||
|
此方案的核心思想是:
|
||||||
|
- 运行时构建:计算图(DAG)不是预先生成的,而是在程序执行过程中动态构建。这允许更灵活的编程,例如,计算的流程可以根据秘密计算的中间结果发生改变。
|
||||||
|
- 通用语言:开发者使用 Python 来编写MPC逻辑。
|
||||||
|
- 分布式框架:底层依赖一个强大的分布式执行框架(Ray @moritz2018raydistributedframeworkemerging)来调度和执行图中的计算任务。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide()[
|
||||||
|
优点:
|
||||||
|
- 灵活性高,易于上手,可以处理具有复杂、数据依赖控制流的算法。
|
||||||
|
- 中文社区,有问题回复较及时。
|
||||||
|
缺点:
|
||||||
|
- 运行时动态调度和框架自身的开销较大(如传输的是整个Python对象),性能不如静态方案。
|
||||||
|
- 框架组件多,使用起来复杂度高。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "静态DAG方案")[
|
||||||
|
主流的静态DAG框架是 MP-SPDZ @mp-spdz。其工作流程完全不同:
|
||||||
|
- 编译时构建:开发者使用一种专门为MPC设计的领域特定语言(DSL)编写协议。
|
||||||
|
- 提前优化:编译器将DSL代码转换成一个固定的、静态的计算图,并进行大量优化(如指令调度、通信批处理)。最终生成高效的字节码。
|
||||||
|
- 虚拟机解释:项目使用C++实现了一个虚拟机,在运行时加载并执行这些预先编译好的字节码。由于所有依赖关系都已确定,执行过程非常高效。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide()[
|
||||||
|
优点:
|
||||||
|
- 性能极高。由于在编译时就掌握了全部计算信息,可以进行全局优化,运行时开销非常小。
|
||||||
|
缺点:
|
||||||
|
- 灵活性差。计算流程必须在编译前完全确定,很难实现依赖于秘密数据的动态分支。
|
||||||
|
- 需要学习相应的DSL。
|
||||||
|
]
|
||||||
|
|
||||||
|
#title-slide[
|
||||||
|
选择快速的通信协议
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide[
|
||||||
|
传统方案是使用同步TCP来实现。但是这个方案因为TCP的握手和同步阻塞问题,性能上比较差。\
|
||||||
|
对此,我们有多种优化方案。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "TCP长链接")[
|
||||||
|
非常简单的一个方式就是使用TCP长连接。这个方案需要额外维护一个连接列表。可以解决频繁建立TCP连接的握手开销。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "TCP长链接代码示例")[
|
||||||
|
核心思路是实现一个 `ConnectionManager`,它内部持有一个 `HashMap` 作为连接池。当需要通信时,我们向管理器请求一个连接。
|
||||||
|
- 如果连接已存在,管理器直接返回它。
|
||||||
|
- 如果不存在,管理器负责建立新连接,存入池中,然后返回。
|
||||||
|
|
||||||
|
这样,无论上层逻辑是发送还是接收,都无需关心连接是否已经建立。
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::net::{TcpStream, ToSocketAddrs};
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
struct ConnectionManager {
|
||||||
|
connections: HashMap<String, TcpStream>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectionManager {
|
||||||
|
// 获取或建立一个新连接
|
||||||
|
// 这个函数体现了“维护链接”:调用者只管要连接,不用管是否已存在
|
||||||
|
fn get_connection<A: ToSocketAddrs + ToString>(
|
||||||
|
&mut self, addr: A
|
||||||
|
) -> io::Result<&mut TcpStream> {
|
||||||
|
let addr_string = addr.to_string();
|
||||||
|
|
||||||
|
// .entry().or_insert_with() 是更地道的写法,这里为了清晰而展开
|
||||||
|
if !self.connections.contains_key(&addr_string) {
|
||||||
|
let stream = TcpStream::connect(addr)?;
|
||||||
|
self.connections.insert(addr_string.clone(), stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(self.connections.get_mut(&addr_string).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "WebSocket:全双工通信")[
|
||||||
|
WebSocket 是另一种在TCP之上,但比原始TCP更现代化的协议。它特别适合需要频繁、实时双向通信的场景。
|
||||||
|
|
||||||
|
- 单次握手: WebSocket通过一个类似HTTP的请求发起握手,一旦成功,连接就升级为WebSocket连接,后续通信不再需要HTTP的开销。
|
||||||
|
- 全双工通信: 连接建立后,客户端和服务器可以随时互相发送消息,实现了真正的双向通信,延迟极低。
|
||||||
|
- 轻量级: 相比HTTP,WebSocket的消息帧头非常小,减少了网络开销。
|
||||||
|
|
||||||
|
对于需要参与方之间进行大量实时交互的MPC协议,WebSocket是一个比传统TCP长连接或HTTP轮询更高效的选择。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "序列化:数据的高效编码")[
|
||||||
|
序列化是将内存中的数据结构(如对象、结构体)转换为可以存储或传输的格式(如字节流)的过程。在MPC中,我们需要在网络间传输大量数据,因此序列化的效率至关重要。
|
||||||
|
|
||||||
|
- 文本格式 (如 JSON):
|
||||||
|
- 优点: 人类可读,易于调试。
|
||||||
|
- 缺点: 体积庞大,解析速度慢,对于性能敏感的MPC通信是巨大的瓶颈。
|
||||||
|
|
||||||
|
- 二进制格式 (如 Protobuf, Bincode):
|
||||||
|
- 优点: 极其紧凑,解析速度飞快,是高性能场景的首选。
|
||||||
|
- 缺点: 人类不可读。
|
||||||
|
|
||||||
|
在Rust生态中,`serde` 框架配合 `bincode` 库是实现高效二进制序列化的黄金搭档。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "序列化代码示例 (Rust)")[
|
||||||
|
通过 `serde`,我们只需在结构体上添加一个派生宏,就能轻松实现序列化和反序列化。
|
||||||
|
```rust
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
// 1. 使用serde的宏来自动实现序列化/反序列化
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct MyData {
|
||||||
|
id: u32,
|
||||||
|
payload: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let original = MyData {
|
||||||
|
id: 101,
|
||||||
|
payload: "hello".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. 使用bincode将结构体序列化为字节
|
||||||
|
let serialized_bytes: Vec<u8> = bincode::serialize(&original).unwrap();
|
||||||
|
println!("Serialized: {:?}", &serialized_bytes);
|
||||||
|
|
||||||
|
// 3. 从字节反序列化回结构体
|
||||||
|
let deserialized: MyData = bincode::deserialize(&serialized_bytes).unwrap();
|
||||||
|
println!("Deserialized: {:?}", &deserialized);
|
||||||
|
|
||||||
|
assert_eq!(original, deserialized);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "流式压缩")[
|
||||||
|
在序列化之后,我们可以通过一些压缩算法来降低传输的数据量,从而减少网络传输时间和带宽消耗。流式压缩特别适用于MPC中需要传输大量中间计算结果的场景。
|
||||||
|
|
||||||
|
优点:
|
||||||
|
- 减少数据量: 直接降低网络传输的数据大小,加快传输速度。
|
||||||
|
- 降低带宽需求: 对于带宽受限的环境尤其重要。
|
||||||
|
- 实时性: 流式压缩/解压缩可以在数据传输的同时进行,不会引入额外的显著延迟。
|
||||||
|
|
||||||
|
常用算法:
|
||||||
|
- Zlib/Deflate: 广泛使用的通用压缩算法,兼顾压缩比和速度。
|
||||||
|
- Snappy: Google开发,以极快的压缩和解压缩速度著称,但压缩比略低于Zlib,适用于对速度要求更高的场景。
|
||||||
|
- LZ4: 另一种非常快速的无损压缩算法,解压缩速度尤其快。
|
||||||
|
|
||||||
|
在选择压缩算法时,需要根据具体的MPC协议和网络环境,权衡压缩比、压缩/解压缩速度以及CPU开销。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "gRPC协议")[
|
||||||
|
gRPC 是由 Google 开发的一个现代、高性能的RPC(远程过程调用)框架,它能很好地解决我们之前提到的一些通信瓶颈。
|
||||||
|
|
||||||
|
- 基于 HTTP/2:
|
||||||
|
- gRPC 使用 HTTP/2 作为其传输协议,天然支持多路复用。这意味着可以在单个TCP连接上同时处理多个请求和响应,彻底解决了队头阻塞问题,也实现了长连接复用。
|
||||||
|
|
||||||
|
- 高效的 Protobuf:
|
||||||
|
- 默认使用 Protocol Buffers (Protobuf) 进行序列化。相比于 JSON,Protobuf 是二进制格式,体积更小、解析更快。
|
||||||
|
|
||||||
|
- 支持流式通信:
|
||||||
|
- 除了常规的“请求-响应”模式,gRPC 还原生支持客户端流、服务端流和双向流。这对于需要连续交换大量数据的MPC场景非常有用。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "QUIC协议")[
|
||||||
|
QUIC 是一个更前沿的传输层协议,它被用作 HTTP/3 的基础。它的设计目标是彻底解决TCP的固有顽疾。
|
||||||
|
|
||||||
|
- 构建于 UDP 之上:
|
||||||
|
- QUIC 抛弃了 TCP,选择在更底层的 UDP 上重新实现了可靠传输、拥塞控制等功能。
|
||||||
|
|
||||||
|
- 解决了真正的队头阻塞:
|
||||||
|
- HTTP/2 在单个TCP连接上多路复用,但如果一个TCP数据包丢失,整个连接上的所有流都必须等待它重传。这是传输层的队头阻塞。
|
||||||
|
- QUIC 将“流”作为一等公民。每个流的数据包被独立处理,一个流的丢包不会阻塞其他流。
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "QUIC协议")[
|
||||||
|
|
||||||
|
- 更快的连接建立:
|
||||||
|
- QUIC 将传输层的握手(类似TCP三次握手)和加密握手(TLS)合并了。对于已有连接,它甚至可以实现 0-RTT(零往返时间)的连接恢复,速度极快。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "协议对比")[
|
||||||
|
为了更好地理解不同通信协议的优劣,我们来对比一下它们在MPC场景下的表现。
|
||||||
|
|
||||||
|
#block[
|
||||||
|
#set text(size: 16pt)
|
||||||
|
#table(
|
||||||
|
columns: (auto, auto, auto, auto),
|
||||||
|
align: (center, left, left, left),
|
||||||
|
// Header
|
||||||
|
[特性], [传统TCP/HTTP/1.1], [gRPC (HTTP/2 over TCP)], [QUIC (HTTP/3 over UDP)],
|
||||||
|
// Rows
|
||||||
|
[传输层], [TCP], [TCP], [UDP],
|
||||||
|
[队头阻塞], [应用层和传输层], [传输层 (TCP HOLB)], [无 (流独立)],
|
||||||
|
[连接建立], [慢 (TCP 3次握手 + TLS)], [慢 (TCP 3次握手 + TLS)], [快 (0-RTT/1-RTT)],
|
||||||
|
[多路复用], [无], [有 (应用层)], [有 (传输层)],
|
||||||
|
[序列化], [通常文本 (如JSON)], [Protobuf (二进制)], [协议无关 (二进制)],
|
||||||
|
[性能], [较低], [中高], [高],
|
||||||
|
[适用场景], [简单请求/响应], [微服务/RPC], [实时通信/高并发]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "异步TCP方案")[
|
||||||
|
使用异步的发送可以让我们无须等待I/O。也就是说,我们在调用`send()`/`recv()`的时候,线程不会一直阻塞,而是会将CPU时间片交给其他任务。
|
||||||
|
|
||||||
|
异步编程有多种模型,最主流的是 `async/await` 方案。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "async/await 方案的优劣")[
|
||||||
|
优点:
|
||||||
|
- 代码直观: 代码的线性逻辑使其看起来像同步代码,非常易于读写和维护。
|
||||||
|
- 资源占用低: 基于无栈协程,单个任务内存开销极小,可以轻松创建海量并发,且上下文切换在用户态完成。
|
||||||
|
- 统一的错误处理: 可以使用语言内建的错误处理机制(如Rust的 `?`),避免了回调地狱中的错误处理难题。
|
||||||
|
|
||||||
|
缺点:
|
||||||
|
- 心智负担: 需要理解 `Future`、执行器等概念,并手动处理CPU密集型任务(放入线程池)。
|
||||||
|
- 函数染色: `async` 关键字具有传染性,`async` 函数不能被同步代码直接调用,反之亦然,割裂了生态。
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide(title: "Rust中的异步实现对比")[
|
||||||
|
在Rust生态中,同时存在Stackful和Stackless两种异步实现,代表了不同的设计哲学。
|
||||||
|
|
||||||
|
Stackful (`may` 框架):
|
||||||
|
- `may` 提供了类似Go Goroutine的体验,每个协程拥有自己的栈。
|
||||||
|
- 开发者可以像写普通同步代码一样进行编程,网络IO等操作会被框架自动调度,对用户透明。
|
||||||
|
- 同样是“无色”函数,不强制区分同步和异步函数。
|
||||||
|
|
||||||
|
Stackless (`tokio` 框架):
|
||||||
|
- 这是Rust官方和社区的主流方案,基于 `async/await` 语法。
|
||||||
|
- 编译器将异步代码转化为状态机,内存占用极低。
|
||||||
|
- 必须遵循 `async/await` 的语法规则,存在“有色”函数问题,但换来了更高的性能和更精细的控制。
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
#title-slide[
|
||||||
|
设计异步化的通信流程
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide()[
|
||||||
|
我们目前学习的方案大部分是同步的协议,即协议的数据几乎要依赖于上一步的状态或结果。
|
||||||
|
Damgård @Dam2009 提出一个全异步的协议设计概念,即协议的正确性不依赖与消息是否在规定时间内到达。
|
||||||
|
同时这篇文章提出#link("https://github.com/mgeisler/viff")[VIFF]框架(现已archive,且继任为MP-SPDZ)
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide()[
|
||||||
|
近年来,还提出了一些新的方案。如hbMPC@hbMPC ,还有Dumbo-MPC@Dumbo-MPC。
|
||||||
|
]
|
||||||
|
|
||||||
|
#title-slide()[
|
||||||
|
总结
|
||||||
|
]
|
||||||
|
|
||||||
|
#slide()[
|
||||||
|
综合前面讨论的通信瓶颈、异步编程思想以及各种优化协议,我们可以勾勒出MPC中异步化通信流程的设计思路:
|
||||||
|
|
||||||
|
- 核心思想:非阻塞与并发
|
||||||
|
- 充分利用异步编程模型,确保通信操作不会阻塞主计算线程,从而提高CPU利用率。
|
||||||
|
|
||||||
|
- 通信调度:DAG驱动
|
||||||
|
- 将通信任务抽象为有向无环图(DAG),通过拓扑排序实现通信的批处理和并发执行,最大限度地减少等待时间。
|
||||||
|
|
||||||
|
- 协议选择:高效可靠
|
||||||
|
- 优先选用基于HTTP/2 (如gRPC) 或 QUIC (如HTTP/3) 的协议,利用其多路复用、快速握手和高效序列化等特性。
|
||||||
|
|
||||||
|
- 连接管理:长连接与复用
|
||||||
|
- 维护连接池,实现长连接的复用,避免频繁建立和关闭连接的开销。
|
||||||
|
]
|
||||||
|
|
||||||
|
// Bibliography
|
||||||
|
#let bib = bibliography("bibliography.bib")
|
||||||
|
#bibliography-slide(bib)
|
||||||
|
|
||||||
BIN
2025-11-21/pics/secretflow.png
Normal file
BIN
2025-11-21/pics/secretflow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
259
2025-11-21/slides_component/figures.typ
Normal file
259
2025-11-21/slides_component/figures.typ
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
#let serial_timeline() = {
|
||||||
|
let cpu-color = blue.lighten(70%)
|
||||||
|
let io-color = green.lighten(70%)
|
||||||
|
let bar-height = 40pt
|
||||||
|
|
||||||
|
// 使用一个水平堆叠来放置时间块
|
||||||
|
stack(
|
||||||
|
dir: ltr, // 布局方向:从左到右
|
||||||
|
spacing: 0pt, // 块之间没有间隔
|
||||||
|
|
||||||
|
// 第一个 CPU 时间片
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: cpu-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "CPU 1")
|
||||||
|
),
|
||||||
|
|
||||||
|
// 第一个 I/O 等待
|
||||||
|
rect(
|
||||||
|
width: 6cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: io-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "I/O 1")
|
||||||
|
),
|
||||||
|
|
||||||
|
// 第二个 CPU 时间片
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: cpu-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "CPU 2")
|
||||||
|
),
|
||||||
|
|
||||||
|
// 第二个 I/O 等待
|
||||||
|
rect(
|
||||||
|
width: 6cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: io-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "I/O 2")
|
||||||
|
),
|
||||||
|
// 示意后续
|
||||||
|
rect(
|
||||||
|
width: 2cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: gray.lighten(80%),
|
||||||
|
stroke: black,
|
||||||
|
align(center, "...")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 添加时间轴标签
|
||||||
|
align(center, [
|
||||||
|
#pad(top: 8pt, text("串行化的计算与处理"))
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
#let batched_timeline() = {
|
||||||
|
let cpu-color = blue.lighten(70%)
|
||||||
|
let io-color = green.lighten(70%)
|
||||||
|
let bar-height = 40pt
|
||||||
|
|
||||||
|
// 使用一个水平堆叠来放置时间块
|
||||||
|
stack(
|
||||||
|
dir: ltr, // 布局方向:从左到右
|
||||||
|
spacing: 0pt, // 块之间没有间隔
|
||||||
|
|
||||||
|
// 第一个 CPU 时间片
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: cpu-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "CPU 1")
|
||||||
|
),
|
||||||
|
// 第二个 CPU 时间片
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: cpu-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "CPU 2")
|
||||||
|
),
|
||||||
|
// 第三个 CPU 时间片
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: cpu-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "CPU 3")
|
||||||
|
),
|
||||||
|
|
||||||
|
// 第一个 I/O 等待
|
||||||
|
rect(
|
||||||
|
width: 6cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: io-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "I/O 1")
|
||||||
|
),
|
||||||
|
|
||||||
|
// 示意后续
|
||||||
|
rect(
|
||||||
|
width: 2cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: gray.lighten(80%),
|
||||||
|
stroke: black,
|
||||||
|
align(center, "...")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 添加时间轴标签
|
||||||
|
align(center, [
|
||||||
|
#pad(top: 8pt, text("批次化的计算与传输"))
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
#let async_timeline() = {
|
||||||
|
let cpu-color = blue.lighten(70%)
|
||||||
|
let io-color = green.lighten(70%)
|
||||||
|
let bar-height = 40pt
|
||||||
|
let max-width = 18cm // 定义一个固定的最大宽度
|
||||||
|
|
||||||
|
// 1. 使用 box 容器定义固定宽度,并让内部元素对齐到左侧
|
||||||
|
box(width: max-width, {
|
||||||
|
align(left, {
|
||||||
|
// 过程 1 (P1)
|
||||||
|
stack(
|
||||||
|
dir: ltr, // 布局方向:从左到右
|
||||||
|
spacing: 0pt, // 块之间没有间隔
|
||||||
|
|
||||||
|
// 第一个 CPU 时间片
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: cpu-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "CPU 1")
|
||||||
|
),
|
||||||
|
// 第一个 I/O 等待
|
||||||
|
rect(
|
||||||
|
width: 6cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: io-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "I/O 1")
|
||||||
|
),
|
||||||
|
// 第四个 CPU 时间片
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: cpu-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "CPU 4")
|
||||||
|
),
|
||||||
|
// 示意后续
|
||||||
|
rect(
|
||||||
|
width: 2cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: gray.lighten(80%),
|
||||||
|
stroke: black,
|
||||||
|
align(center, "...")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// 过程 2 (P2)
|
||||||
|
stack(
|
||||||
|
dir: ltr, // 布局方向:从左到右
|
||||||
|
spacing: 0pt, // 块之间没有间隔
|
||||||
|
|
||||||
|
// 占位符 (已完成/占用时间),用于错位对齐
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: white, // 改为白色以匹配截图视觉效果
|
||||||
|
stroke: black,
|
||||||
|
align(center, "")
|
||||||
|
),
|
||||||
|
// 第二个 CPU 时间片
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: cpu-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "CPU 2")
|
||||||
|
),
|
||||||
|
// 第二个 I/O 等待
|
||||||
|
rect(
|
||||||
|
width: 6cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: io-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "I/O 2")
|
||||||
|
),
|
||||||
|
// 示意后续
|
||||||
|
rect(
|
||||||
|
width: 2cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: gray.lighten(80%),
|
||||||
|
stroke: black,
|
||||||
|
align(center, "...")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// 过程 3 (P3)
|
||||||
|
stack(
|
||||||
|
dir: ltr, // 布局方向:从左到右
|
||||||
|
spacing: 0pt, // 块之间没有间隔
|
||||||
|
// 占位符 1
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: white,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "")
|
||||||
|
),
|
||||||
|
// 占位符 2
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: white,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "")
|
||||||
|
),
|
||||||
|
// 第三个 CPU 时间片
|
||||||
|
rect(
|
||||||
|
width: 3cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: cpu-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "CPU 3")
|
||||||
|
),
|
||||||
|
// 第三个 I/O 等待
|
||||||
|
rect(
|
||||||
|
width: 6cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: io-color,
|
||||||
|
stroke: black,
|
||||||
|
align(center, "I/O 3")
|
||||||
|
),
|
||||||
|
// 示意后续
|
||||||
|
rect(
|
||||||
|
width: 2cm,
|
||||||
|
height: bar-height,
|
||||||
|
fill: gray.lighten(80%),
|
||||||
|
stroke: black,
|
||||||
|
align(center, "...")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 添加时间轴标签
|
||||||
|
align(center, [
|
||||||
|
#pad(top: 8pt, text("异步化的计算与传输"))
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
103
2025-11-21/template.typ
Normal file
103
2025-11-21/template.typ
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#import "@preview/typslides:1.3.0": *
|
||||||
|
|
||||||
|
// Project configuration
|
||||||
|
#show: typslides.with(
|
||||||
|
ratio: "16-9",
|
||||||
|
theme: "bluey",
|
||||||
|
font: "Fira Sans",
|
||||||
|
font-size: 20pt,
|
||||||
|
link-style: "color",
|
||||||
|
show-progress: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
// The front slide is the first slide of your presentation
|
||||||
|
#front-slide(
|
||||||
|
title: "This is a sample presentation",
|
||||||
|
subtitle: [Using _typslides_],
|
||||||
|
authors: "A. Manjavacas",
|
||||||
|
info: [#link("https://github.com/manjavacas/typslides")],
|
||||||
|
)
|
||||||
|
|
||||||
|
// Custom outline
|
||||||
|
#table-of-contents()
|
||||||
|
|
||||||
|
// Title slides create new sections
|
||||||
|
#title-slide[
|
||||||
|
This is a _Title slide_
|
||||||
|
]
|
||||||
|
|
||||||
|
// A simple slide
|
||||||
|
#slide[
|
||||||
|
- This is a simple `slide` with no title.
|
||||||
|
- #stress("Bold and coloured") text by using `#stress(text)`.
|
||||||
|
- Sample link: #link("typst.app").
|
||||||
|
- Link styling using `link-style`: `"color"`, `"underline"`, `"both"`
|
||||||
|
- Font selection using `font: "Fira Sans"`, `size: 21pt`.
|
||||||
|
|
||||||
|
#framed[This text has been written using `#framed(text)`. The background color of the box is customisable.]
|
||||||
|
|
||||||
|
#framed(title: "Frame with title")[This text has been written using `#framed(title:"Frame with title")[text]`.]
|
||||||
|
]
|
||||||
|
|
||||||
|
// Focus slide
|
||||||
|
#focus-slide[
|
||||||
|
This is an auto-resized _focus slide_.
|
||||||
|
]
|
||||||
|
|
||||||
|
// Blank slide
|
||||||
|
#blank-slide[
|
||||||
|
- This is a `#blank-slide`.
|
||||||
|
|
||||||
|
- Available #stress[themes]#footnote[Use them as *color* functions! e.g., `#reddy("your text")`]:
|
||||||
|
|
||||||
|
#framed(back-color: white)[
|
||||||
|
#bluey("bluey"), #reddy("reddy"), #greeny("greeny"), #yelly("yelly"), #purply("purply"), #dusky("dusky"), darky.
|
||||||
|
]
|
||||||
|
|
||||||
|
// #show: typslides.with(
|
||||||
|
// ratio: "16-9",
|
||||||
|
// theme: "bluey",
|
||||||
|
// ...
|
||||||
|
// )
|
||||||
|
|
||||||
|
|
||||||
|
- Or just use *your own theme color*:
|
||||||
|
- `theme: rgb("30500B")`
|
||||||
|
]
|
||||||
|
|
||||||
|
// Slide with title
|
||||||
|
#slide(title: "Outlined slide", outlined: true)[
|
||||||
|
- Check out the *progress bar* at the bottom of the slide.
|
||||||
|
|
||||||
|
#h(1cm) `show-progress: true`
|
||||||
|
|
||||||
|
- Outline slides with `outlined: true`.
|
||||||
|
|
||||||
|
#grayed([This is a `#grayed` text. Useful for equations.])
|
||||||
|
#grayed($ P_t = alpha - 1 / (sqrt(x) + f(y)) $)
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
// Columns
|
||||||
|
#slide(title: "Columns")[
|
||||||
|
|
||||||
|
#cols(columns: (2fr, 1fr, 2fr), gutter: 2em)[
|
||||||
|
#grayed[Columns can be included using `#cols[...][...]`]
|
||||||
|
][
|
||||||
|
#grayed[And this is]
|
||||||
|
][
|
||||||
|
#grayed[an example.]
|
||||||
|
]
|
||||||
|
|
||||||
|
- Custom spacing: `#cols(columns: (2fr, 1fr, 2fr), gutter: 2em)[...]`
|
||||||
|
|
||||||
|
- Sample references: @typst, @typslides.
|
||||||
|
- Add a #stress[bibliography slide]...
|
||||||
|
|
||||||
|
1. `#let bib = bibliography("you_bibliography_file.bib")`
|
||||||
|
2. `#bibliography-slide(bib)`
|
||||||
|
]
|
||||||
|
|
||||||
|
// Bibliography
|
||||||
|
#let bib = bibliography("bibliography.bib")
|
||||||
|
#bibliography-slide(bib)
|
||||||
46
README.md
Normal file
46
README.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# 组会ppt
|
||||||
|
|
||||||
|
使用typst来制作ppt。模板使用typslides:1.3.0。
|
||||||
|
|
||||||
|
## 初始化新ppt
|
||||||
|
|
||||||
|
使用组会当天的日期作为文件名,主文件命名为main.typ。
|
||||||
|
使用以下命令初始化。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
typst init @preview/typslides:1.3.0
|
||||||
|
mv typslides/* .
|
||||||
|
cp main.typ template.typ
|
||||||
|
```
|
||||||
|
|
||||||
|
然后引入codly和设定字体
|
||||||
|
|
||||||
|
```typst
|
||||||
|
#import "@preview/typslides:1.3.0": *
|
||||||
|
#import "@preview/codly:1.3.0": *
|
||||||
|
#import "@preview/codly-languages:0.1.1": *
|
||||||
|
#show: codly-init.with()
|
||||||
|
#codly(languages: codly-languages)
|
||||||
|
#show raw: set text(font: ("0xProto Nerd Font", "WenQuanYi Micro Hei"))
|
||||||
|
|
||||||
|
// Project configuration
|
||||||
|
#show: typslides.with(
|
||||||
|
ratio: "16-9",
|
||||||
|
theme: "yelly",
|
||||||
|
font: ("0xProto Nerd Font","WenQuanYi Micro Hei"),
|
||||||
|
font-size: 20pt,
|
||||||
|
link-style: "color",
|
||||||
|
show-progress: true,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 语气设定
|
||||||
|
|
||||||
|
考虑到听众可能在代码与架构设计方面不是很了解,在讲解具体技术方面需要更加通俗易懂,必要的时候结合简单的python来说明。
|
||||||
|
|
||||||
|
文字风格要全文一致,不要加入很多我的内容没有的风格,不要混杂中英文。
|
||||||
|
|
||||||
|
## ppt格式说明
|
||||||
|
|
||||||
|
在中文内容中,不要使用黑体加粗的格式(双星号,**xx**),也不要用斜体的格式(单星号*xx*)。就使用普通的正文格式。
|
||||||
|
单页ppt内容不要过多。如果过多,则新建一页ppt。不然自动分页将会打乱排版。
|
||||||
Reference in New Issue
Block a user