trpl-zh-cn/ch16-04-extensible-concurrency-sync-and-send.html
2025-05-23 15:28:58 +00:00

243 lines
16 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>使用 Sync 与 Send Traits 的可扩展并发 - Rust 程序设计语言 简体中文版</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="ferris.css">
<link rel="stylesheet" href="theme/2018-edition.css">
<link rel="stylesheet" href="theme/semantic-notes.css">
<link rel="stylesheet" href="theme/listing.css">
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust 程序设计语言 简体中文版</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/KaiserY/trpl-zh-cn/tree/main" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/KaiserY/trpl-zh-cn/edit/main/src/ch16-04-extensible-concurrency-sync-and-send.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h2 id="使用-send-和-sync-trait-的可扩展并发"><a class="header" href="#使用-send-和-sync-trait-的可扩展并发">使用 <code>Send</code><code>Sync</code> trait 的可扩展并发</a></h2>
<blockquote>
<p><a href="https://github.com/rust-lang/book/blob/main/src/ch16-04-extensible-concurrency-sync-and-send.md">ch16-04-extensible-concurrency-sync-and-send.md</a>
<br>
commit 56ec353290429e6547109e88afea4de027b0f1a9</p>
</blockquote>
<p>Rust 的并发模型中一个有趣的方面是:我们之前讨论的几乎所有内容,都属于标准库,而不是语言本身的内容。由于不需要语言提供并发相关的基础设施,并发方案不受标准库或语言所限:我们可以编写自己的或使用别人编写的并发功能。</p>
<p>然而,在内嵌于语言而非标准库的关键并发概念中,有属于 <code>std::marker</code><code>Send</code><code>Sync</code> trait。</p>
<h3 id="通过-send-允许在线程间转移所有权"><a class="header" href="#通过-send-允许在线程间转移所有权">通过 <code>Send</code> 允许在线程间转移所有权</a></h3>
<p><code>Send</code> 标记 trait 表明实现了 <code>Send</code> 的类型值的所有权可以在线程间传送。几乎所有的 Rust 类型都是<code>Send</code> 的,不过有一些例外,包括 <code>Rc&lt;T&gt;</code>:这是不能实现 <code>Send</code> 的,因为如果克隆了 <code>Rc&lt;T&gt;</code> 的值并尝试将克隆的所有权转移到另一个线程,这两个线程都可能同时更新引用计数。为此,<code>Rc&lt;T&gt;</code> 被实现为用于单线程场景,这时不需要为拥有线程安全的引用计数而付出性能代价。</p>
<p>因此Rust 类型系统和 trait bound 确保永远也不会意外的将不安全的 <code>Rc&lt;T&gt;</code> 在线程间发送。当尝试在示例 16-14 中这么做的时候,会得到错误 <code>the trait Send is not implemented for Rc&lt;Mutex&lt;i32&gt;&gt;</code>。而使用实现了 <code>Send</code><code>Arc&lt;T&gt;</code> 时,就没有问题了。</p>
<p>任何完全由 <code>Send</code> 的类型组成的类型也会自动被标记为 <code>Send</code>。几乎所有基本类型都是 <code>Send</code>除了第二十章将会讨论的裸指针raw pointer</p>
<h3 id="sync-允许多线程访问"><a class="header" href="#sync-允许多线程访问"><code>Sync</code> 允许多线程访问</a></h3>
<p><code>Sync</code> 标记 trait 表明一个实现了 <code>Sync</code> 的类型可以安全的在多个线程中拥有其值的引用。换一种方式来说,对于任意类型 <code>T</code>,如果 <code>&amp;T</code><code>T</code> 的不可变引用)实现了 <code>Send</code> 的话 <code>T</code> 就实现了 <code>Sync</code>,这意味着其引用就可以安全的发送到另一个线程。类似于 <code>Send</code> 的情况,基本类型都实现了 <code>Sync</code>,完全由实现了 <code>Sync</code> 的类型组成的类型也实现了 <code>Sync</code></p>
<p>智能指针 <code>Rc&lt;T&gt;</code> 也没有实现 <code>Sync</code>,出于其没有实现 <code>Send</code> 相同的原因。<code>RefCell&lt;T&gt;</code>(第十五章讨论过)和 <code>Cell&lt;T&gt;</code> 系列类型没有实现 <code>Sync</code><code>RefCell&lt;T&gt;</code> 在运行时所进行的借用检查也不是线程安全的。<code>Mutex&lt;T&gt;</code> 实现了 <code>Sync</code>,正如 <a href="ch16-03-shared-state.html#%E5%9C%A8%E7%BA%BF%E7%A8%8B%E9%97%B4%E5%85%B1%E4%BA%AB-mutext">“在线程间共享 <code>Mutex&lt;T&gt;</code></a> 部分所讲的它可以被用来在多线程中共享访问。</p>
<h3 id="手动实现-send-和-sync-是不安全的"><a class="header" href="#手动实现-send-和-sync-是不安全的">手动实现 <code>Send</code><code>Sync</code> 是不安全的</a></h3>
<p>通常并不需要手动实现 <code>Send</code><code>Sync</code> trait因为完全由实现了 <code>Send</code><code>Sync</code> 的类型组成的类型,自动实现了 <code>Send</code><code>Sync</code>。因为它们是标记 trait甚至都不需要实现任何方法。它们只是用来加强并发相关的不可变性的。</p>
<p>手动实现这些标记 trait 涉及到编写不安全的 Rust 代码,第二十章将会讲述具体的方法;当前重要的是,在创建新的由不是 <code>Send</code><code>Sync</code> 的部分构成的并发类型时需要多加小心,以确保维持其安全保证。<a href="https://doc.rust-lang.org/nomicon/index.html">“The Rustonomicon”</a> 中有更多关于这些保证以及如何维持它们的信息。</p>
<h2 id="总结"><a class="header" href="#总结">总结</a></h2>
<p>这不会是本书最后一个出现并发的章节:下一章会我们会专注于异步编程,并且第二十一章的项目会在更现实的场景中使用这些概念,而不像本章中讨论的这些小例子。</p>
<p>正如之前提到的,因为 Rust 本身很少有处理并发的部分内容,有很多的并发方案都由 crate 实现。它们比标准库要发展的更快;请在网上搜索当前最新的用于多线程场景的 crate。</p>
<p>Rust 提供了用于消息传递的信道,和像 <code>Mutex&lt;T&gt;</code><code>Arc&lt;T&gt;</code> 这样可以安全的用于并发上下文的智能指针。类型系统和借用检查器会确保这些场景中的代码,不会出现数据竞争和无效的引用。一旦代码可以编译了,我们就可以坚信这些代码可以正确的运行于多线程环境,而不会出现其他语言中经常出现的那些难以追踪的 bug。并发编程不再是什么可怕的概念无所畏惧地并发吧</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch16-03-shared-state.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="ch17-00-async-await.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="ch16-03-shared-state.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="ch17-00-async-await.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
<script src="ferris.js"></script>
</div>
</body>
</html>