ltaodream

  • 2024-07-22
  • 回复了主题帖: 读书活动入围名单:《大模型时代的基础架构:大模型算力中心建设指南》

    个人信息无误,确认可以完成阅读分享计划

  • 2024-07-12
  • 回复了主题帖: 《Rust实战》书友互动第十集:进程、线程和容器

    吾妻思萌 发表于 2024-6-24 10:56 提问: 之前做WEB server都是调试时候用ctrl+C直接中断掉,似乎没想过如何让其能够优雅的中断。 哪位 ... 你可以用Rust标准库中的tokio异步运行时和signal-hook库来优雅地处理一下SIGINT(Ctrl+C)信号

  • 回复了主题帖: 《Rust实战》书友互动第十一集:内核

    吾妻思萌 发表于 2024-6-28 09:02 一个小问题: 作为业余感兴趣去学习Rust的有一丝丝编程基础的人,Rust是否是太过于coding硬核了,像是很 ... 没必要,可以先从更容易入门的比如go,进行入手,再来进行rust

  • 回复了主题帖: 《Rust实战》书友互动剧终:信号、中断和异常

    吾妻思萌 发表于 2024-7-5 08:02 多线程中断该怎么调度啊,感觉很复杂啊?要把任务压到栈里吗   多线程是通过std::thread模块来实现的,但直接中断一个线程(如Java中的Thread.stop())在Rust中并不直接支持,因为这样做可能引发数据竞争和其他未定义行为   在Rust中,处理线程中断和任务调度通常依靠以下几种策略: 通信(Communication): 使用std::sync中的同步原语(如Mutex, Arc, Condvar)或std::mpsc(多生产者单消费者通道)来协调线程间的消息传递。当需要停止一个任务时,可以发送一个特定的信号或消息给工作线程,让它优雅地自我结束。 标志(Flags): 可以通过共享的原子布尔标志(std::sync::atomic::AtomicBool)来通知线程应该停止工作。线程在执行任务时定期检查这个标志,一旦发现应停止,则自行退出。 JoinHandle与线程退出: 创建线程时会得到一个JoinHandle,你可以使用它来等待线程结束,但不能直接中断线程。一种间接的方法是在线程函数中检查外部条件(如上述的标志),或者在主线程中等待所有子线程完成(join())。 异步编程: Rust的异步编程模型(async/await)和tokio或async-std这样的库提供了更高级的并发和任务管理机制。在异步世界中,任务(通常称为“future”)可以被取消,而且异步运行时提供了更灵活的调度能力。 外部库: 使用如crossbeam这样的第三方库可以提供更多高级的并发工具,如线程池和工作窃取调度器,这些可以帮助更高效地管理和调度线程。

  • 2024-06-10
  • 回复了主题帖: 《Rust实战》书友互动第八集:网络,这个很熟悉...

    ccccccc@ 发表于 2024-6-7 15:41 在 Rust 中,如何使用异步编程来高效地处理大量并发的网络连接,同时又可以确保数据的可靠传输和低延迟响应 ... 使用异步运行时:Rust 的异步编程通常依赖于异步运行时,如 tokio 或 async-std。这些运行时提供了执行异步任务和处理 I/O 操作的基础设施。 异步 I/O:使用异步 I/O 库,如 tokio::net 或 async-std::net,来创建和处理网络连接。这些库允许你以非阻塞的方式读写数据。 使用 Future 和 async/await:Rust 的 Future trait 和 async/await 语法使得编写异步代码变得简单和直观。Future 代表了一个可能还没有完成的计算,而 async 函数返回一个 Future。 连接池:为了高效地管理大量连接,可以使用连接池来复用连接,减少创建和销毁连接的开销。 背压(Backpressure):在处理大量并发请求时,背压是一种重要的机制,用于防止生产者发送数据的速度超过消费者处理的速度。 错误处理:确保你的异步代码能够妥善处理错误,例如使用 Result 类型和 ? 操作符来传播错误。 超时和重试策略:设置合理的超时时间,并根据需要实现重试逻辑,以确保数据的可靠传输。 使用消息队列:在处理大量并发请求时,可以使用消息队列来缓冲请求,然后异步地处理它们。 并发控制:使用 Rust 的并发原语,如 Mutex、RwLock 或 Arc,来安全地在多个线程或任务之间共享数据。 性能监控和优化:使用性能监控工具来分析你的异步代码,并根据需要进行优化。 使用第三方库:利用 Rust 生态系统中的第三方库,如 hyper 用于 HTTP 客户端和服务端的开发,serde 用于序列化和反序列化数据等。

  • 回复了主题帖: 《Rust实战》书友互动第八集:网络,这个很熟悉...

    网络协议的字节数据有特殊要求,那么在Rust网络编程中,有哪些最佳实践

  • 2024-05-30
  • 回复了主题帖: 《Rust实战》书友互动第七集:文件与存储

    qinyunti 发表于 2024-5-27 23:10 主要是出于可移植性考虑,同时Path提供方法给用户直接使用比直接处理字符串意图更明显方便阅读,也避免手 ... 感觉书里边不是很详细,我试着用ai了一下: Rust 中使用 Path 而不是直接处理字符串的原因有几个: 类型安全:Path 是一个结构体,它提供了一个抽象层,用于表示文件系统的路径。这使得 Rust 编译器可以在编译时检查路径的合法性,而不是在运行时。通过使用 Path,Rust 可以确保路径是有效的,并且避免了一些常见的错误,比如路径遍历攻击。 跨平台兼容性:不同的操作系统有不同的文件系统路径表示方法。例如,Windows 使用反斜杠 \ 作为路径分隔符,而 Unix-like 系统使用正斜杠 /。Path 抽象允许 Rust 程序在不同的平台上透明地处理路径,而不需要编写特定于平台的代码。 功能丰富:Path 提供了多种方法来操作和查询路径,比如 join(连接路径)、parent(获取父目录)、extension(获取文件扩展名)等。这些方法使得路径操作更加直观和方便。 编码处理:在处理文件路径时,路径中的字符可能包含特殊字符或非ASCII字符。Path 可以处理这些情况,确保路径在不同环境中正确地被解释和使用。 性能:虽然字符串也可以表示路径,但是直接使用字符串可能会导致额外的字符串操作和转换,这可能会影响性能。Path 作为专门用于路径的结构体,可以优化内部表示,从而提高性能。 语义清晰:使用 Path 可以使得代码更加清晰,因为它明确表示了这是一个文件系统路径,而不是一般的字符串。这有助于提高代码的可读性和可维护性。 总的来说,Path 在 Rust 中提供了一个类型安全、功能丰富、跨平台的抽象,用于处理文件系统路径,这使得 Rust 程序更加健壮和易于维护。

  • 2024-05-27
  • 回复了主题帖: 《Rust实战》书友互动第七集:文件与存储

    为什么Rust使用Path,而不是直接处理字符串?

  • 回复了主题帖: 《Rust实战》Rust->物化主义者box指针的智能

    damiaa 发表于 2024-5-27 09:10 看到esp32 idf 5.31里面都有rust了。不知道能不能用了。 学起来

  • 2024-05-26
  • 发表了主题帖: 《Rust实战》Rust->物化主义者box指针的智能

    # 《Rust实战》Rust->物化主义者box指针的智能 指针一般存的是另一个变量在内存里的地址值 在Rust里的智能指针,比传统的指针多了一些所谓的 1. 添加额外信息 2. 管理引用计数 3. 资源自动回收 先看看box指针,box指针会强制资源在堆上 Box ```cpp fn foo() -> Box { let i = 100u32; let b = Box::new(i); let j=i; b } fn main() { let i_addr = foo(); println!("{i_addr}"); } ``` 这个程序可以编译通过,因为box实例对于整数是copy,对于对于已知尺寸的数据类型创建会在栈上,在Box::new(i)后,会将栈上的i copy到堆,将指针返回给i_addr ```cpp struct P { x: u32, y: u32 } fn foo() -> Box { let p = P {x: 10, y: 20}; let b = Box::new(p); let q = p; b } fn main() { let _p = foo(); } ``` 这个程序编译通不过,因为相对上一个程序,p是move行为 box解引用的时候这两种也会有区别,对于move类型的解引用会释放所有权

  • 2024-05-23
  • 回复了主题帖: 《Rust实战》书友互动第六集:内存,有啥你不熟悉的吗?

    yangjiaxu 发表于 2024-5-23 10:29 问: rust最优越感的就是针对内存的处理了,可以说是确保了内存的安全性和线程安全性,那么rust与C语言 ... 在 C 语言中,需要手动管理内存,容易导致内存泄漏、野指针、缓冲区溢出等问题。而在rust中因为存在生命周期和所有权会在大括号结束的时候自动回收

  • 回复了主题帖: 《Rust实战》书友互动第六集:内存,有啥你不熟悉的吗?

    IC爬虫 发表于 2024-5-23 10:28 哪位大佬总结一下Rust管理内存有哪些方式? 主要通过所有权、借用、生命周期等机制来实现。所有权机制确保在程序中只有一个所有者可以拥有并修改数据,避免了出现多个指针同时访问和修改同一块内存的情况,从而避免了常见的内存安全问题,例如空指针解引用、野指针等。生命周期用于描述某个引用的有效期,在编译时检查引用是否合法。生命周期的存在使得 Rust 能够在编译阶段就能够发现潜在的内存安全问题,并防止出现空指针解引用等问题。还有就是跟C++一样的RAII机制

  • 回复了主题帖: 《Rust实战》书友互动第六集:内存,有啥你不熟悉的吗?

    智能指针和其他编程语言的指针有何不同呢?

  • 2024-05-20
  • 回复了主题帖: 有没有大佬能帮忙内推实习

    考研吧,不考研没办法

  • 2024-05-19
  • 发表了主题帖: 《Rust实战》Rust->物化主义者的秉性

    # 《Rust实战》Rust->物化主义者的秉性 大家可以跟着操作操作理解!一定要操作起来!!! [Rust在线编译器网址](https://play.rust-lang.org/ "Rust在线编译器网址") 在[《Rust实战》Rust->极致物化主义者!](https://bbs.eeworld.com.cn/thread-1282271-1-1.html "《Rust实战》Rust->极致物化主义者!")这篇文章中我们了解了Rust所有权的规则。一般来说,对于固定尺寸类型(比如u32),会默认放在栈上;而非固定尺寸类型(比如String)(非显式clone操作),会默认创建在堆上,成为堆上的一个资源,然后在栈上用一个局部变量来指向它。 例子 : 复制所有权:将a复制了一份,a、b各自拥有相应资源的所有权 ```cpp fn main() {     let a = 99u32;     let b = a;     println!("{a}");     println!("{b}"); } ``` 移动所有权操作(转交,所有权只有一份) ```cpp fn foo(s: String) -> String{ println!("{s}"); s } fn main() { let s1 = String::from("hello eeworld !"); let s1 = foo(s1); foo(s1); } ``` 究竟是移动所有权操作(转交,所有权只有一份),还是复制所有权操作(复制一份,各自拥有相应资源的所有权): 1. 所有的整数类型,比如 u32 2. 布尔类型 bool 3. 浮点数类型,比如 f32、f64 4. 字符类型 char 5. 由以上类型组成的元组类型 tuple,如(i32, i32, char) 6. 由以上类型组成的数组类型 array,如 [9; 100] 7. 不可变引用类型 & 除此之外,其他类型默认都是做移动所有权的操作。

  • 发表了主题帖: 《Rust实战》Rust->极致物化主义者!

    # 《Rust实战》Rust->极致物化主义者! 所有权,是 Rust 的精髓所在。大家一起来学习一下吧! 一般来说,对于固定尺寸类型(比如u32),会默认放在栈上;而非固定尺寸类型(比如String),会默认创建在堆上,成为堆上的一个资源,然后在栈上用一个局部变量来指向它。 拿Java来举例,在将一个变量赋值给另一个变量的时候,对于 int 这类固定尺寸类型,在复制给另一个变量的时候,会直接复制它的值。在面对 Object 这种复杂对象的时候,默认只会复制这个 Object 的引用给另一个变量。这个引用的值(内存地址)就存在栈上的局部变量里面。因为如果那个 Object 占用的内存很大,每一次重新赋值,就把那个对象重新拷贝一次,也就是完全克隆,是非常低效的。 ## Rust 对于Rust来说: 1. 固定尺寸类型在复制给另一个变量的时候,也是直接复制它的值。 2. 对于字符串这种动态长度的类型来说, ## 所有权 Rust 将值看作资源资源,所有权就是拥有这个资源的权利。一个变量拥有一个资源的所有权,那它就要负责那个资源的回收、释放。 **Rust 基于所有权的定义,是精髓所在。** 定义: 1. Rust 中,每一个值都有一个所有者。 2. 任何一个时刻,一个值只有一个所有者。 3. 当所有者所在**作用域(scope)**结束的时候,其管理的值会被一起释放掉。 作用域:在 Rust 中,一个所有权型变量的作用域,就是它定义时所在的那个最里层的花括号括起的部分,从变量创建时开始,到花括号结束的地方。 例子: 变量的 Shadowing:变量名和老的相同,原来的变量被遮盖,访问不到 ```cpp fn main() {     let x = 5;     println!("The value of x is: {x}");     let x = 6;     println!("The value of x is: {x}"); } ``` ## 回收 Rust的回收机制是RAII(Resource Acquisition Is Initialization)(C++也是这样的),堆内存资源随着关联的栈上局部变量一起被回收。不需要像C那样,手动调用 free() 函数去释放堆中的字符串资源。 例子: 在这个例子中的第二行中,s2 持有字符串的所有权,此时,s1处于无效状态。到程序结束,s1 所对应的局部变量的内存空间被回收,s2 及 s2 所指向的字符串内存,也被回收掉了。 ```cpp fn main() {     let s1 = String::from("hello eeworld !");     let s2 = s1;     println!("{s2}"); } ``` Rust和其他语言不一样的地方 例子: 这个程序在println!("{s1}");这一行会报错,因为在foo(s1)调用函数的时候,所有权已经被转交了 ```cpp fn foo(s: String) {     println!("{s}"); } fn main() {     let s1 = String::from("hello eeworld !");     foo(s1);     println!("{s1}"); } ``` 像下边程序这样调用两次也是不可以的,跟上边同理 ```cpp fn foo(s: String) {     println!("{s}"); } fn main() {     let s1 = String::from("hello eeworld !");     foo(s1);     foo(s1); } ``` 如果想把所有权传递给第二个函数,需要把所有权转移出来 ```cpp fn foo(s: String) -> String{     println!("{s}");     s } fn main() {     let s1 = String::from("hello eeworld !");     let s1 = foo(s1);     foo(s1); } ``` 核心俗话来说就是 **一个苹果,你给了别人,那你就没有了。一个知识,我教给了你,我们都会得到。** **rust采用了物化的前者,其他语言采用了知识思想化的后者** 所以大家要注意,**Rust是一个极致物化主义者!!!**

  • 2024-05-13
  • 回复了主题帖: 《Rust实战》书友互动第五集:深入理解数据

    为什么两个完全相同的二进制串能表示完全不同的两个数?

  • 回复了主题帖: 《Rust实战》书友互动第五集:深入理解数据

    nemon 发表于 2024-5-13 18:56 如何把一个4位字节序列转换成32位整数?怎么理解转换是unsafe的? 可以使用 from_be_bytes 或 from_le_bytes 函数。这两个函数分别接受大端和小端字节序的输入。将字节序列转换为整数是一种可能涉及到内存安全的操作。如果字节序列的长度不正确或者字节序列包含无效数据,则可能导致未定义的行为,例如访问非法内存地址或者返回错误的结果。因此,在 Rust 中,将字节序列转换为整数被认为是一种 "unsafe" 操作,需要使用 unsafe 关键字来标记。这意味着程序员必须保证输入的数据是有效和正确的,否则可能会导致安全问题。

  • 2024-05-11
  • 回复了主题帖: 《Rust实战》书友互动第四集:生命周期、所有权和借用

    一个由固定尺寸类型组成的结构体变量,在赋值给另一个变量时,采用的是移动方式还是复制方式?

  • 回复了主题帖: 《Rust实战》书友互动第四集:生命周期、所有权和借用

    所有权在Rust 语言中非常重要,用于管理程序中使用的资源。这些资源可以是堆上的动态分配的内存资源,也可以是栈上的内存资源,或者是其他的系统资源,比如 IO 资源。

最近访客

< 1/1 >

统计信息

已有13人来访过

  • 芯积分:114
  • 好友:--
  • 主题:8
  • 回复:36

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言