当前位置: 首页 > news >正文

北京电商网站开发公司江西网络推广seo

北京电商网站开发公司,江西网络推广seo,怎样运营推广网站,宣传片拍摄报价明细喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 16.3.1. 使用共享来实现并发 还记得Go语言有一句名言是这么说的:Do not commun…

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
请添加图片描述

16.3.1. 使用共享来实现并发

还记得Go语言有一句名言是这么说的:Do not communicate by sharing memory; instead, share memory by communicating.(不要用共享内存来通信,要用通信来共享内存)

上一篇文章就是使用通信的方式来实现并发的。这一篇文章讲一下如何使用共享内存的方式来实现并发。Go语言不建议使用这种方式,Rust支持通过共享状态来实现并发。

上一篇文章讲的Channel类似单所有权:一旦值的所有权转移至Channel,就无法使用它了。共享内存并发类似于多所有权:多个线程可以同时访问同一块内存。

16.3.2. 使用Mutex来只允许一个线程来访问数据

Mutex是mutual exclusion(互斥锁)的简写。

在同一时刻,Mutex只允许一个线程来访问某些数据。

想要访问数据,线程必须首先获取互斥锁(lock),在Rust里就是调用lock方法获得。lock数据结构是Mutex的一部分,它能跟踪谁对数据拥有独占访问权。Mutex通常被描述为:通过锁定系统来保护它所持有的数据。

16.3.3. Mutex的两条规则

  • 在使用数据之前,必须尝试获取锁(lock)。
  • 使用完Mutex所保护的数据,必须对数据进行解锁,以便其他线程可以获取锁。

16.3.4. Mutex<T>的API

通过Mutex::new函数来创建Mutex<T>,其参数就是要保护的数据。Mutex<T>实际上是一个智能指针。

在访问数据前,通过lock方法来获取锁,这个方法会阻塞当前线程的运行。lock方法也可能会失败,所以返回的值被Result包裹,如果成功其值,Ok变体附带的值的类型就为MutexGuard(智能指针,实现了DerefDrop)。

看个例子:

use std::sync::Mutex;fn main() {let m = Mutex::new(5);{let mut num = m.lock().unwrap();*num = 6;}println!("m = {m:?}");
}
  • 使用Mutex::new创建了一个互斥锁,其保护的数据是5,赋给m。所以m的类型是MutexGuard<i32>
  • 后面使用{}创建了新的小作用域,在小作用域里使用lock方法获取值,使用unwrap进行错误处理。由于MutexGuard实现了Deref trait,我们就可以获得内部数据的引用。所以num是一个可变引用。
  • 在小作用域内还使用了解引用*来修改数据的值为6。
  • 由于MutexGuard实现了Drop trait,所以在小作用域结束后会自动解锁。
  • 最后打印了修改后的互斥锁内的内容。

输出:

m = Mutex { data: 6 }

16.3.5. 多线程共享Mutex<T>

看个例子:

use std::sync::Mutex;
use std::thread;fn main() {let counter = Mutex::new(0);let mut handles = vec![];for _ in 0..10 {let handle = thread::spawn(move || {let mut num = counter.lock().unwrap();*num += 1;});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Result: {}", *counter.lock().unwrap());
}
  • counter实际上就是一个计数器,只是使用了Mutex包裹以更好地在多线程中调用,刚开始的值是0
  • handle目前是一个空Vector
  • 下面通过从0到10(不包括10)的循环创建了10个线程,把每个线程得到的handle放到空集合handles里。
  • 在线程的闭包里,我们的意图是把counter这个互斥锁转移到闭包里(所以使用了move关键字),然后获取互斥锁,然后修改它的值,每个线程都加1。当线程执行完后,num会离开作用域,互斥锁被释放,其他线程就可以使用了。
  • 从0到10(不包括10)的循环里还遍历了handles,使用join方法,这样等每个handle所对应的线程都结束后才会继续执行。
  • 最后在主线程里尝试获得counter的互斥锁,然后把它打印出来。

输出:

$ cargo runCompiling shared-state v0.1.0 (file:///projects/shared-state)
error[E0382]: borrow of moved value: `counter`--> src/main.rs:21:29|
5  |     let counter = Mutex::new(0);|         ------- move occurs because `counter` has type `Mutex<i32>`, which does not implement the `Copy` trait
...
8  |     for _ in 0..10 {|     -------------- inside of this loop
9  |         let handle = thread::spawn(move || {|                                    ------- value moved into closure here, in previous iteration of loop
...
21 |     println!("Result: {}", *counter.lock().unwrap());|                             ^^^^^^^ value borrowed here after move|
help: consider moving the expression out of the loop so it is only moved once|
8  ~     let mut value = counter.lock();
9  ~     for _ in 0..10 {
10 |         let handle = thread::spawn(move || {
11 ~             let mut num = value.unwrap();|For more information about this error, try `rustc --explain E0382`.
error: could not compile `shared-state` (bin "shared-state") due to 1 previous error

错误是在前一次循环中已经把所有权移到前一次的那个线程里了,而这一次循环就没发再获得所有权了。

那么如何把counter放到多个线程,也就是让多个线程拥有它的所有权呢?

16.3.6. 多线程的多重所有权

在15章讲了一个多重所有权的智能指针叫Rc<T>,把counterRc包裹即可:

let counter = Rc::new(Mutex::new(0));

在循环里,需要把克隆传进线程,这里用了类型遮蔽把新counter值设为旧counter的引用:

let counter = Rc::clone(&counter);

修改后的代码(记得在使用前引入Rc):

use std::rc::Rc;
use std::sync::Mutex;
use std::thread;fn main() {let counter = Rc::new(Mutex::new(0));let mut handles = vec![];for _ in 0..10 {let counter = Rc::clone(&counter);let handle = thread::spawn(move || {let mut num = counter.lock().unwrap();*num += 1;});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Result: {}", *counter.lock().unwrap());
}

输出:

error[E0277]: `Rc<Mutex<i32>>` cannot be sent between threads safely--> src/main.rs:11:36|
11 |           let handle = thread::spawn(move || {|                        ------------- ^------|                        |             ||  ______________________|_____________within this `{closure@src/main.rs:11:36: 11:43}`| |                      || |                      required by a bound introduced by this call
12 | |             let mut num = counter.lock().unwrap();
13 | |
14 | |             *num += 1;
15 | |         });| |_________^ `Rc<Mutex<i32>>` cannot be sent between threads safely|= help: within `{closure@src/main.rs:11:36: 11:43}`, the trait `Send` is not implemented for `Rc<Mutex<i32>>`, which is required by `{closure@src/main.rs:11:36: 11:43}: Send`
note: required because it's used within this closure--> src/main.rs:11:36|
11 |         let handle = thread::spawn(move || {|                                    ^^^^^^^
note: required by a bound in `spawn`--> /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/thread/mod.rs:688:1For more information about this error, try `rustc --explain E0277`.
error: could not compile `shared-state` (bin "shared-state") due to 1 previous error

看报错信息的这部分:`Rc<Mutex<i32>>` cannot be sent between threads safelyRc<Mutex<i32>>不能在线程间安全地传递。编译器也告诉我们了原因:the trait `Send` is not implemented for `Rc<Mutex<i32>>`Rc<Mutex<i32>>没有实现send trait(下一篇文章会讲到)。只有实现send的类型才能在线程间安全地传递。

其实在第15章讲Rc<T>也说到了它不能用于多线程场景:Rc<T>不能安全地跨线程共享。它不能确保计数的更改不会被另一个线程中断。这可能会导致错误的计数,进而导致内存泄漏或在我们完成之前删除某个值。我们需要的是一种与Rc<T>完全相同的类型,但它以线程安全的方式更改引用计数。

那么多线程应该用什么呢?有一个智能指针叫做Arc<T>可以胜任这个场景。

16.3.7. 使用Arc<T>来进行原子引用计数

Arc<T>Rc<T>类似,但是它可以用于并发场景。Arc的A指的是Atomic(原子的),这意味着它是一个原子引用计数类型,原子是另一种并发原语。这里不对Arc<T>做过于详细的介绍,只需要知道原子像原始类型一样工作,但可以安全地跨线程共享,其余信息详见Rust官方文档。

那么为什么所有的基础类型都不是原子的?为什么标准库不默认使用Arc<T>?这是因为:

  • Arc<T>的功能需要以性能作为代价
  • Arc<T>Rc<T>的API都是相同的

既然Arc<T>Rc<T>的API都是相同的,那么先前的代码就很好改了(记得在使用前引入Arc):

use std::sync::{Arc, Mutex};
use std::thread;fn main() {let counter = Arc::new(Mutex::new(0));let mut handles = vec![];for _ in 0..10 {let counter = Arc::clone(&counter);let handle = thread::spawn(move || {let mut num = counter.lock().unwrap();*num += 1;});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Result: {}", *counter.lock().unwrap());
}

16.3.8. RefCell<T>/Rc<T> vs. Mutex<T>/Arc<T>

Mutex<T>提供了内部可变性,和Cell家族一样。我们一般使用RefCell<T>包裹Rc<T>以获得一个有内部可变性的共享所有权数据类型。同样的,使用Mutex<T>可以改变Arc<T>里面的内容。

当使用Mutex<T>时,Rust 无法保护您免受各种逻辑错误的影响。使用Rc<T>会带来创建引用循环的风险,其中两个Rc<T>值相互引用,从而导致内存泄漏。同样, Mutex<T>也存在产生死锁(deadlock) 的风险。当一个操作需要锁定两个资源并且两个线程各自获取其中一个锁,导致它们永远等待对方时,就会发生这种情况。Mutex<T>MutexGuard的标准库API文档提供了有用的信息。详见:Mutex<T>API文档和MutexGuardAPI文档。

http://www.yidumall.com/news/44906.html

相关文章:

  • 网站cms系统 开源网站推广的策略
  • 拱墅区做网站重庆百度推广开户
  • 汕头站扩建招标百度客服人工电话
  • 郑州网站设计的公司百度关键词查询网站
  • 专注邯郸建设手机网站app拉新推广怎么做
  • asp做的网站如何发布seo优化及推广如何运营
  • 网站建设 图片百度推广手机客户端
  • 四川超宇建设集团网站免费公司网站建站
  • 网站开发阶段怎么做测试搜索引擎优化网站排名
  • 关于公司网站建设情况的汇报百度今日排行榜
  • 怎么做网站一张图论坛推广方案
  • 星光影视园网站建设案例上海网站seo策划
  • 电子商务网站建设的概要设计博客优化网站seo怎么写
  • 浙江网站建设公司电话公司全网推广
  • 在线播放的网站怎么做技术短期培训班
  • 黑龙江省住房和城乡建设厅网络优化工程师
  • 做海报挣钱的网站盘多多搜索引擎入口
  • WordPress全站广告广东东莞疫情最新情况
  • 免签约收款WordPress优化神马排名软件
  • 云虚拟主机怎么建网站谷歌推广费用多少
  • 做产品网站要备案吗查淘宝关键词排名软件
  • 游戏网站策划营销策划方案ppt模板
  • 网站建设项目背景宁波网站优化公司哪家好
  • 百度官方下载seo的概念是什么
  • 为什么做织梦网站时图片出不来seo排名点击软件推荐
  • 建自己的网站用多少钱头条权重查询
  • 在自己电脑建设网站大型营销型网站制作
  • 做网站学生作业百度灰色关键词代发
  • 什么是静态网页佛山seo培训
  • 江门企业网站建设营业推广策略