入职第一天,老板要试一下我的水平,于是给我布置了一个任务,写一个 Hello World
吧,但是公司用的是 Rust。
我心想,这不是分分钟的事情嘛,很快程序就写好了:
rust 代码解读复制代码fn main() {
println!("Hello World!")
}
然后老板说,前端怎么对接你这个接口?啊,你不早说,是写一个接口啊。行吧,那就用 Axum 框架写一个吧,也不是啥难事。虽然不是分分钟,但是三五分钟还是可以搞定的:
rust 代码解读复制代码use axum::Router;
use axum::routing::get;
#[tokio::main]
async fn main() {
let app = Router::new().route("/", async { "Hello World"});
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
然后和老板去回报进度:老板,接口版本的 Hello World
完成了。只见老板眉头一皱:小苏,做一个事情要考虑周全,你这个版本虽然完成了功能,有没有想过安全性呢?给返回 Hello World
加密!
啥!Hello World
也要加密啊,行吧。那就上 AES256-GCM 吧,军规级的,够安全了吧?
rust 代码解读复制代码use aes_gcm::{Aes256Gcm, Key, KeyInit, Nonce};
use hex::encode;
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(encrypted_hello));
// 省略没有改变的代码
}
async fn encrypted_hello() -> String {
let message = b"Hello, World!";
// 省略三五行加密的模版代码,只是为了说明这里实现了加密
let ciphertext = cipher.encrypt(nonce, message.as_ref()).unwrap();
format!("encrypted: {}", encode(&ciphertext))
}
心里想,这回老板应该满意了吧。满心欢喜地找老板交差,仿佛升职加薪迎娶老板女儿的日子马上就要到来了。
给老板演示之后,老板欣然一笑,转而又语重心长地说道:安全是安全了,只是......我的心提到了嗓子眼,只是啥?!
老板停顿了好一会,继续说道:只是你有没有考虑过,Axum 是一个协程框架,你将 CPU 密集的计算放在协程里,会不会阻塞?
天啊,流氓不可怕,啊不,老板不可怕,只怕老板懂技术,似懂非懂最可怕。我就写一个 Hello World
而已啊,需要那么复杂嘛?!行,我接着改。
从老板办公室到工位这一路有点漫长,我的脑子飞快地转动着,Axum 框架是基于 Tokio 协程运行时,Tokio 好像提供了一个 API,可以让将一些密集型的代码放到线程里执行......啊,想到了 task::spawn_blocking()
!
rust 代码解读复制代码async fn encrypted_hello() -> String {
task::spawn_blocking(|| {
let message = b"Hello, World!";
// 继续省略
let ciphertext = cipher.encrypt(nonce, message.as_ref()).unwrap();
format!("encrypted: {}", encode(&ciphertext))
}).await.unwrap()
}
走,去老板办公室,我得意地一笑,你难不倒我,你女儿迟早是我的。“老板,我想到办法了,把加密的重活交给 tokio 的线程去执行,就不会阻塞协程了!” 老板,看了一眼我,说道:
“你没看到我和小米同学在谈公事嘛,你先出去!”
我瞟了一眼,小米同学是挺漂亮......感性的......
过了大半个小时,老板来到我的工位前,对我说:“这个版本兼顾了安全和性能,还是不错的,但是......”。老板怎么总是喜欢停顿加但是呢?
“但是,你有没有想过,你把密集型计算委托给 Tokio,如果大家都这么做的话,会导致公共线程池饱和......”。老板,这些是 AI 和你说的嘛?
没办法,继续改,既然不能用公共线程池来做,就要自己启用一个线程,然后和协程之间通过 Channel 进行通信......好像有一个东西叫做 mpsc
......我只是写一个 Hello World
啊!天啊,迎娶老板女儿啊,不是西天取经啊。
rust 代码解读复制代码use std::thread;
use aes_gcm::{Aes256Gcm, Key, KeyInit, Nonce};
use aes_gcm::aead::Aead;
use axum::Router;
use axum::routing::get;
use hex::encode;
use rand::RngCore;
use rand::rngs::OsRng;
use tokio::sync::{mpsc, oneshot};
struct EncryptTask {
message: Vec<u8>,
responder: oneshot::Sender<String>
}
#[tokio::main]
async fn main() {
let (tx, mut rx) = mpsc::channel::(100);
thread::spawn(move || {
while let Some(task) = rx.blocking_recv() {
let key = Key::::from_slice(&[0u8; 32]);
let cipher = Aes256Gcm::new(key);
let mut nonce_bytes = [0u8; 12];
OsRng.fill_bytes(&mut nonce_bytes);
let nonce = Nonce::from_slice(&nonce_bytes);
let ciphertext = cipher.encrypt(nonce, task.message.as_ref()).unwrap();
let result = format!("nonce: {}, chipher_text: {}", encode(&nonce), encode(&ciphertext));
let _ = task.responder.send(result);
}
});
let app = Router::new().route("/", get(move || encrypted_hello(tx.clone())));
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn encrypted_hello(tx: mpsc::Sender) -> String {
let (resp_tx, resp_rx) = oneshot::channel();
let task = EncryptTask {
message: b"Hello World".to_vec(),
responder: resp_tx,
};
tx.send(task).await.unwrap();
resp_rx.await.unwrap()
}
经过一番折腾,终于完成了。看了一眼窗外,一天过去了,天都黑了。老板和小米同学一前一后走出办公室,正要下班。我抓紧喊了一声,老板我完成了!
老板对我挥了挥手,说道:我想了一下,Hello World 没必要做的那么复杂,你还是改回原来的版本吧.....
评论记录:
回复评论: