V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lsk569937453
V2EX  ›  Rust

自己用 rust 踩了不少坑,希望<Rust-笔记>能抛砖引玉。

  •  2
     
  •   lsk569937453 · 58 天前 · 2553 次点击
    这是一个创建于 58 天前的主题,其中的信息可能已经有所发展或是发生改变。

    笔记在github,觉得有用的给个 Star 。

    Rust 笔记

    此笔记只是记录在使用 rust 遇到的一些坑或者一些比较好用的工具或者其他的东东。本人主要用 rust 开发网络相关的程序或者桌面程序,因此不涉及音视频和其他的领域。

    好用的工具

    工程相关

    cross:跨平台编译,甚至在 github actions 也可以直接用cross

    tarpaulin:单元测试覆盖率。

    min-sized-rust:减少编译后的二进制文件大小。

    网络编程相关

    常用的 tokio 异步运行时不多说了。http web 框架可能有争议,比如 warp,actix-web 可能性能会好一点,但是 axum 写起来更简单。sqlx 虽然直接写 sql ,相信我,其他的 ORM 框架更难用!

    tracing:tokio 的日志模块,非常强大,在 tokio 运行时中强烈建议使用 tracing 配合 tracing-appender 做日志。

    hyper:开发底层 http1 、http2 必备的 crates 。

    axum:http web 框架,CRUD boy 必备。

    sqlx:sqlx 框架,CRUD boy 必备。

    reqwest:http client 。

    clap:开发终端工具/命令行程序必备。

    openssl:openssl 相关,由于很多 crate 是基于 openssl 的,一般都是作为 vendor 引入编译的时候直接一起编译。

    一些常见的问题和反直觉

    一些常见的问题

    我不会生命周期,看了'a,'static,&'static,T: 'a 头疼怎么办?

    如果用 rust 做 web 程序,根本用不到生命周期。我至今还不懂生命周期,照样用 rust 开发 web ,技术栈就是 axum+tracing+sqlx+reqwest 。

    hyper 做 server 会不会内存泄漏?

    先说答案,默认的 allocator ,在并发数升高后会导致内存飙升,且并发数降低时,内存不会降低。当前的解决方案是使用 MiMalloc(本人已经验证过,效果良好)。具体的问题讨论在这里

    反直觉

    多线程通信我直接用 Arc::Mutex 是不是太 Low 了,使用 RwLock 或者dashmap更好一点?

    • 如果你肯定你的锁是读超多写很少的场景,那么直接用 RwLock 。
    • 如果你不确定你的锁的使用场景,请使用互斥锁。

    互斥锁并不慢,我使用互斥锁来存储 redis 的所有数据,最后多线程的压测结果,rcache 的吞吐量是 redis 的两倍。

    异步运行时一定优于同步吗?异步运行时一定快吗?

    先说结果,不一定,而且异步的程序相比同步的程序肯定要慢的。

    什么时候使用异步运行时开发呢?

    • 网络编程就是一个非常好的例子,网络程序中,程序大量的时间都在读取 IO ,因此可以用异步获取超高的吞吐量。

    什么时候使用同步运行时开发程序呢?

    • 算法大赛,需要你写一个 rust 算法比比谁的算法快。
    • 1brc

    tokio::sync::Mutex 性能很低。

    常用场景:我看 tokio 里面有 Mutex 我就直接用了,没想那么多。

    这个 Mutex 的性能很低,相比 std::sync::Mutex 性能低一倍以上。如果对性能敏感的应用可以直接在异步运行时中使用 std::sync::Mutex 。感兴趣的可以看一下 tokio 的关于 Mutex 的文档。压测的程序在这里.但是在异步运行时中使用 std 的 Mutex 时需要注意的原则是“锁保护的代码段不跨越 await”。

    收集到的释放锁的方式。

    • 使用 drop 关键字释放锁
    • a.lock().clone 也可以释放锁
    • 使用大括号将加锁的代码括起来,代码执行出大括号则自动释放锁

    我看 future 提供了很多方法。这两种写法有性能差别吗?

    let a=b.await?;
    let c=a.read().await?;
    
    let c=b.and_then(|d|d.read()).await?
    

    看上去第二种写法只 await 一次,其实如上两种写法性能上没有本质差别,第二种写法只是使用了 future 这个 crates 提供的内部的状态机。

    15 条回复    2024-07-14 18:42:28 +08:00
    wikilab
        1
    wikilab  
       58 天前 via Android
    多谢分享
    imMetaverse
        2
    imMetaverse  
       58 天前
    多谢分享
    yazoox
        3
    yazoox  
       58 天前
    > MiMalloc
    我看你链接的帖子里,好像只有一个人使用这个工具有效,其他人都没有效果。
    你能多分享一些你使用的心得和技巧么? thx
    ch3nOr
        4
    ch3nOr  
       58 天前
    多谢分享
    daniel11
        5
    daniel11  
       58 天前
    多谢分享 想了解下是什么背景情况下选择用 Rust 的 axum+tracing+sqlx+reqwest 开发 web 程序的
    changdig
        6
    changdig  
       58 天前
    多谢,对于 rust 开发 web 还是有点犹豫,感觉没啥必要
    445141126
        7
    445141126  
       58 天前
    @yazoox 应该是有效果的
    > I was having the same issue and switched to the MiMalloc allocator. It releases memory instantly - from 2GB when underload back to 50MB when idle, constrast to the default allocator which peaks at 3GB and 1.7GB when idle. MiMalloc does not only consume less memory but also performs better in my case, bench tested both on my Linux machine and Docker container with resource limited to 1CPU 1GB. I think I'm going to stick with MiMalloc for now.
    lsk569937453
        8
    lsk569937453  
    OP
       58 天前
    @yazoox 直接全局修改 allocator 即可,就加两行代码。
    #[global_allocator]
    static GLOBAL: MiMalloc = MiMalloc;

    测试的场景是:先把压测工具的并发数设置为 2000 ,此时 hyper 进程占用的内存是 1G 。然后将并发数设置为 200 ,此时 hyper 的内存降低为 80M 。测试完成。
    hasdream
        9
    hasdream  
       58 天前
    多谢分享
    OBJECTION
        10
    OBJECTION  
       58 天前
    最近也是闲着无聊再看 rust 先收藏了
    xiangchen2011
        11
    xiangchen2011  
       58 天前
    写的挺好的
    Cambra1n
        12
    Cambra1n  
       58 天前
    谢谢分享,最近也想学习学习,但不清楚在后端和大数据中间件方面有哪些优势。
    artiga033
        13
    artiga033  
       58 天前 via Android
    sqlx 直接写 sql 还是有点无法接受,一般我宁愿选择 mongoDB 。

    个人推荐个 ORM 框架 sea-orm,底层是 sqlx ,可以用 rust 写数据库的迁移文件,整体体验和.NET 的 entity framework 很类似
    PTLin
        14
    PTLin  
       57 天前
    补充一下,现代的 Mutex 其实内部都会自旋一段时间,获取不到锁并不会直接进行系统调用而休眠,因为现在处理器速度非常快,很多时候自旋的时候锁就被释放了。
    tokio 的 Mutex 使用原则基本上是:假如是多 task 操作一个 Vec 那种,临界区非常小,并且不跨越 await (因为 await 点可能出现一个线程加锁,另一个线程释放的问题,所以 std Mutex guard 是!Send ,导致整个 future 都是!Send) ,直接用 std 的 Mutex 就好。但是假如是独占了一个需要长时间使用数据,例如异步的数据库链接,这种才需要使用 tokio Mutex 。
    tairan2006
        15
    tairan2006  
       55 天前
    感觉学 rust 用来写 web 真的是浪费时间……
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1161 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 23:51 · PVG 07:51 · LAX 16:51 · JFK 19:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.