陈天 · Rust 编程第一课
陈天
Tubi TV 研发副总裁
23195 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 65 讲
基础篇 (21讲)
陈天 · Rust 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

05|get hands dirty:做一个图片服务器有多难?

在 main.rs 使用新的引擎
添加新的图片引擎
在 Engine 中使用 spec
为 spec 实现 SpecTransform trait
添加新的 proto
避免不必要的网络请求
图片引擎
定义接口
考虑架构的可扩展性
图片服务器的核心部分
324 行代码
水到渠成
学习曲线
编译难通过
享受编写 Rust 代码的过程
揪出大多数错误
数据类型的转换
分离具体的图片处理引擎和主流程
解决实际问题的能力
抽象能力
换图片引擎
添加新功能
缓存
trait
protobuf
功能
代码量
Rust 学习
编译器的优势
From / TryFrom trait
Engine trait
Rust 强大的表现力
思考题
Thumbor 项目
总结

该思维导图由 AI 生成,仅供参考

你好,我是陈天。
上一讲我们只用了百来行代码就写出了 HTTPie 这个小工具,你是不是有点意犹未尽,今天我们就来再写一个实用的小例子,看看 Rust 还能怎么玩。
再说明一下,代码看不太懂完全没有关系,先不要强求理解,跟着我的节奏一行行写就好,先让自己的代码跑起来,感受 Rust 和自己常用语言的区别,看看代码风格是什么样的,就可以了
今天的例子是我们在工作中都会遇到的需求:构建一个 Web Server,对外提供某种服务。类似上一讲的 HTTPie ,我们继续找一个已有的开源工具用 Rust 来重写,但是今天来挑战一个稍大一点的项目:构建一个类似 Thumbor 的图片服务器。

Thumbor

Thumbor 是 Python 下的一个非常著名的图片服务器,被广泛应用在各种需要动态调整图片尺寸的场合里。
它可以通过一个很简单的 HTTP 接口,实现图片的动态剪切和大小调整,另外还支持文件存储、替换处理引擎等其他辅助功能。我在之前的创业项目中还用过它,非常实用,性能也还不错。
我们看它的例子:
http://<thumbor-server>/300x200/smart/thumbor.readthedocs.io/en/latest/_images/logo-thumbor.png
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

使用Rust语言构建图片服务器的思路和方法 本文介绍了使用Rust语言构建一个类似图片服务器的项目,以Thumbor图片服务器为例,展示了如何设计一个易用、简洁的接口来实现图片的动态转换。作者首先分析了图片转换服务的难点,提出了使用列表来表述图片处理的有序操作,并使用protobuf来描述数据结构,以实现可扩展的图片处理参数。接着讨论了如何在HTTP服务器中处理路由,以及如何提供LRU缓存来优化原始图片的获取过程。文章还介绍了使用Rust语言构建图片服务器的思路和方法,以Thumbor图片服务器为例,展示了如何设计一个易用、简洁的接口来实现图片的动态转换。通过分析图片转换服务的难点,提出了使用列表来表述图片处理的有序操作,并使用protobuf来描述数据结构,以实现可扩展的图片处理参数。同时,讨论了在HTTP服务器中处理路由,以及提供LRU缓存来优化原始图片的获取过程。文章鼓励读者用Rust语言构建这个工具,并期望用大约200行代码实现需求。整体而言,本文以实际项目为例,展示了使用Rust语言构建图片服务器的思路和方法,为读者提供了一种新的技术实践思路。文章还介绍了使用Rust语言构建图片服务器的思路和方法,以Thumbor图片服务器为例,展示了如何设计一个易用、简洁的接口来实现图片的动态转换。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(77)

  • 最新
  • 精选
  • 大汉十三将
    置顶
    这一章学了 3 天, 终于能看懂一点了 : - 1.2: 开始接触, 一脸懵逼, 所有的代码个顶个的都看不懂, 极其痛苦的 1 个半小时 - 1.3: 通过强制自己问 chatgpt: xx 这段代码是干什么用的, 强制自己去熟悉 rust 的相关 library, 终于看懂了一些文件的一部分代码 2 h - 1.4: 基本把不会的都询问 Chatgpt 整理了一遍, 逻辑上都顺了, 剩下一些小的语法问题需要继续记笔记 1.5 h

    编辑回复: 棒,get hands dirty 系列很多同学刚看都说很难看不懂,你是第一个把自己的学习过程贴上来的,给你置顶啦,学习思路正好也可以供其他同学参考~

    2023-01-04归属地:北京
    2
    7
  • 葡萄
    看老师的项目,语言已经不是最重要的了。思路和组织结构真是赏心悦目。

    作者回复: 谢谢赏识。我希望这门课不光能教会大家语言本身,更重要的是如何用语言提供的能力优雅地解决实际问题。有的人能用 C 写出面向对象的代码;有的人能用 Java 写出 Fortran 的感觉。Rust 为我们提供了强大的抽象能力,我们要用好它。:)

    2021-09-01
    2
    55
  • pedro
    最让人无法接受的点: ```shell du -h -d 1 ./target 395M ./target/rls 901M ./target/debug 1.3G ./target ```

    作者回复: 如果你觉得每个项目都有个 target,项目多了不好清理,那么可以编辑 ~/.cargo/config,让所有项目的编译结果都放在同一个目录下(不过这样无法同时编译多个项目,cargo 有文件锁): ``` [build] target-dir = "/Users/tchen/.target" ``` 如果你觉得编译后的结果太大,倒也不用担心,release build 比较小,目前 9M,这里还可以用很多方法进一步优化: ``` ❯ ls -l ~/.target/release/thumbor -rwxr-xr-x 2 tchen staff 9562656 Aug 30 12:09 /Users/tchen/.target/release/thumbor* ``` 至于如果你觉得编译的中间文件太大,nodejs 的 node_modules,python 的 virtualenv,都是吃磁盘的主。:)

    2021-09-01
    3
    21
  • wzx
    为什么在main.rs中并没有见到引入: use tracing_subscriber; use reqwest; 却可以直接使用?

    作者回复: reqwest 和 tracing_subscriber 已经是顶级 namespace,如果你想直接使用 get,你可以 use reqwest::get,但你如果就是要通过 crate 名引入其功能,可以直接使用,就跟我们可以直接用 std::sync::Arc 一样。Rust 下只要你加了依赖,对应的依赖就可以访问了,不存在 import 的过程。use 只是简化 namespace。

    2021-09-02
    20
  • Christian
    感概什么时候才能达到老师这样的高度?

    作者回复: 苦干,实干,巧干。让勤勉追上时间的脚步。:)

    2021-09-01
    16
  • Fan
    逻辑清晰,喜欢这种教学方式。从项目,问题入手,也不是纠结于语法细节。

    作者回复: 👍

    2021-09-01
    14
  • Michael
    Rust,相比起有运行时Go语言,运行效率不再话下。另外,作为现代系统级编程语言,在工程实践,依赖管理,相比起C、C++要好很多,但是比起Go稍微复杂一些。 语言学习难度还是挺大的,很多新概念,新名词都要理解,不过写起来还是挺爽的。用半年实践反复学习实践,希望能啃下这门语言。 希望老师从先行者的角度,对一些难点,易错点,平时不容易接触的到的地方给学生们做下讲解,看书和看网上资料千篇一律,没什么新奇的地方,大多讲的不够透。

    作者回复: 嗯,会的,后续的文章我们紧扣数据结构在栈和堆上的关系展开,我觉得这很重要,但似乎没有人这样讲解。接下来的课程你会慢慢看到的。

    2021-09-03
    8
  • Quincy
    请问老师还有什么新的图片引擎吗?可以推荐一个吗?在 github 和 crates.io 上没有找到相似的,谢谢老师

    作者回复: 几个选择: - 你可以直接在 image 库上实现 - 使用 imagemagick: https://github.com/nlfiedler/magick-rust - 使用 opencv: https://github.com/twistedfall/opencv-rust - 使用 piet: https://github.com/linebender/piet - 或者任何 C/C++ image 库(需要做一下 rust binding)

    2021-09-01
    2
    8
  • Quincy
    添加新功能: 1. 首先添加新的 proto ```proto message PaddingBottom { uint32 x = 1; } // 一个 spec 可以包含上述的处理方式之一 message Spec { oneof data { ... Watermark watermark = 7; // 处理水印 PaddingBottom paddingBottom = 8; // 填充图片 } } ``` 2. 定义新的 spec然后为 spec 实现 SpecTransform trait 和一些辅助函数 ```rust // File: 在文件 `pb/mod.rs` 中 // 提供一些辅助函数,让创建一个 spec 的过程简单一些 impl Spec { ... pub fn new_padding_bottom(x: u32) -> Self { Self { data: Some(spec::Data::PaddingBottom(PaddingBottom { x })) } } } ``` 3. 最后在 Engine 中使用 spec ```rust impl Engine for Photon { fn apply(&mut self, specs: &[Spec]) { for spec in specs.iter() { match spec.data { Some(spec::Data::Crop(ref v)) => self.transform(v), ... Some(spec::Data::PaddingBottom(ref v)) => self.transform(v), _ => {} ... impl SpecTransform<&PaddingBottom> for Photon { fn transform(&mut self, op: &PaddingBottom) { let rgba = Rgba::new(255_u8, 255_u8, 255_u8, 255_u8); let img = transform::padding_bottom(&mut self.0, op.x, rgba); self.0 = img; } } ``` 4. 在 main.rs 函数中使用 ```rust // 调试辅助函数 fn print_test_url(url: &str) { use std::borrow::Borrow; let spec1 = Spec::new_resize(500, 800, resize::SampleFilter::CatmullRow); let spec2 = Spec::new_watermark(20, 20); let spec3 = Spec::new_padding_bottom(100); // new let spec4 = Spec::new_filter(filter::Filter::Marine); let image_spec = ImageSpec::new(vec![spec1, spec2, spec3, spec4]); let s: String = image_spec.borrow().into(); let test_image = percent_encode(url.as_bytes(), NON_ALPHANUMERIC).to_string(); println!("test url: http://localhost:3000/image/{}/{}", s, test_image); } ```

    作者回复: Wow,你是第一个把思考题答案贴出来的!看得出理解了代码,并且还研究了一下 photon_rs 的能力。非常棒!

    2021-09-01
    2
    8
  • 茶底
    逻辑清晰,泪目了,我咋就这么菜

    编辑回复: 哈哈大佬也是坚持不懈学出来的,看到差距就已经看到学习方向了,加油💪

    2021-09-01
    6
收起评论
显示
设置
留言
77
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部