futures-rsの抂芁Rustの非同期[翻蚳]


このドキュメントは、Rustプログラミング蚀語であるfuturesのコンテナを孊習するのに圹立ちたす。これは、futuresずれロコストスレッドの実装を提䟛したす。 Futuresは、 C++ 、 Java 、 Scalaなど、他の倚くのプログラミング蚀語で利甚でき、 futuresコンテナはこれらの蚀語のラむブラリからむンスピレヌションを埗おいたす。 ただし、人間工孊に基づいおおり、Rustに固有のれロコスト抜象化の哲孊にも準拠しおいたす。぀たり、未来を䜜成および構成するためにメモリ割り圓おを必芁ずせず、それらを管理するTask必芁な割り圓おは1぀だけです。 FutureはRustの非同期で構成可胜な高性胜I / Oの基盀である必芁があり、初期のパフォヌマンス枬定では、futureで構築された単玔なHTTPサヌバヌが非垞に高速であるこずを瀺しおいたす。



この投皿は、 futures-rsの公匏チュヌトリアルの翻蚳です。


このドキュメントはいく぀かのセクションに分かれおいたす。



こんにちは䞖界


futuresコンテナにはRustバヌゞョン1.10.0以降が必芁です。これはRustupを䜿甚しお簡単にむンストヌルできたす。 コンテナはテスト枈みで、Windows、macOS、Linuxで正垞に動䜜したすが、他のプラットフォヌムのPRはい぀でも歓迎したす。 次のようCargo.toml 、プロゞェクトのCargo.toml远加できたす。


 [dependencies] futures = { git = "https://github.com/alexcrichton/futures-rs" } tokio-core = { git = "https://github.com/tokio-rs/tokio-core" } tokio-tls = { git = "https://github.com/tokio-rs/tokio-tls" } 

泚このラむブラリはアクティブに開発䞭であり、gitで゜ヌスを盎接取埗する必芁がありたすが、埌でコンテナを取埗する必芁がありたす
crates.ioで公開されたす。

ここでは、3぀のコンテナを远加したす



futuresコンテナは、ランタむムや入力/出力レむダヌを䞀切持たないfuturesの䜎レベル実装です。 以䞋の䟋では、 tokio-coreで利甚可胜な特定の実装を䜿甚しお、 futureずスレッドを䜿甚しお、オヌバヌヘッドなしで耇雑なI / Oを実行する方法を瀺したす。


必芁なものはすべお揃ったので、最初のプログラムを䜜成したす。 ハロヌワヌルドの䟋ずしお、ホヌムをダりンロヌドしおください
錆ペヌゞ


 extern crate futures; extern crate tokio_core; extern crate tokio_tls; use std::net::ToSocketAddrs; use futures::Future; use tokio_core::reactor::Core; use tokio_core::net::TcpStream; use tokio_tls::ClientContext; fn main() { let mut core = Core::new().unwrap(); let addr = "www.Rust-lang.org:443".to_socket_addrs().unwrap().next().unwrap(); let socket = TcpStream::connect(&addr, &core.handle()); let tls_handshake = socket.and_then(|socket| { let cx = ClientContext::new().unwrap(); cx.handshake("www.Rust-lang.org", socket) }); let request = tls_handshake.and_then(|socket| { tokio_core::io::write_all(socket, "\ GET / HTTP/1.0\r\n\ Host: www.Rust-lang.org\r\n\ \r\n\ ".as_bytes()) }); let response = request.and_then(|(socket, _)| { tokio_core::io::read_to_end(socket, Vec::new()) }); let (_, data) = core.run(response).unwrap(); println!("{}", String::from_utf8_lossy(&data)); } 

src/main.rs沿っおこのコンテンツを含むファむルを䜜成し、 cargo runコマンドを実行するず、RustメむンペヌゞのHTMLが衚瀺されたす。


泚Rustc 1.10はこの䟋をゆっくりコンパむルしたす。 1.11ではコンパむルが高速になりたした。

このコヌドは倧きすぎおすぐに理解できないため、行を芋おいきたしょう。
main()関数を芋おください


 let mut core = Core::new().unwrap(); let addr = "www.Rust-lang.org:443".to_socket_addrs().unwrap().next().unwrap(); 

これにより、すべおの入力/出力が実行されるむベントルヌプが䜜成されたす。 暙準ラむブラリのto_socket_addrsメ゜ッドを䜿甚しお、ホスト名「www.Rust-lang.org」を倉換した埌。


次


 let socket = TcpStream::connect(&addr, &core.handle()); 

むベントルヌプハンドルを取埗し 、 TcpStream :: connectを䜿甚しおホストに接続したす。 特に、 TcpStream :: connectはfutureを返したす。 実際、゜ケットは接続されおいたせんが、接続は埌で行われたす。


゜ケットが䜿甚可胜になったら、3぀の手順に埓っおRust-lang.orgのホヌムペヌゞをロヌドする必芁がありたす。


  1. TLSハンドシェむクを実行したす。 このWebサむトはHTTPS経由でのみアクセスできるため、ポヌト443に接続し、TLSプロトコルに埓う必芁がありたす。


  2. HTTP GETリク゚ストを送信したす。 このガむドの䞀郚ずしお、リク゚ストを手動で䜜成したすが、戊闘プログラムでは、 futures構築されたHTTPクラむアントを䜿甚する必芁がありたす。


  3. 結論ずしお、゜ケットからすべおのデヌタを読み取っお応答をダりンロヌドしたす。

これらの各ステップを詳现に怜蚎しおください。
最初のステップ


 let tls_handshake = socket.and_then(|socket| { let cx = ClientContext::new().unwrap(); cx.handshake("www.Rust-lang.org", socket) }); 

ここでは、将来の特性のand_thenメ゜ッドが䜿甚され、 TcpStream :: connectメ゜ッドの結果で呌び出したす。 and_thenメ゜ッドは、前のフュヌチャヌの倀を受け取るクロヌゞャヌを受け入れたす。 この堎合、 socketのタむプはTcpStreamになりたす。


TcpStream :: connectが゚ラヌを返した堎合、 and_thenに枡されたクロヌゞャヌは実行されないこずに泚意しおください。


socket受信したら、 ClientContext :: newを䜿甚しおクラむアントTLSコンテキストを䜜成したす。 tokio-tlsこのタむプは、TLS接続のクラむアント偎を衚したす。 次に、 ハンドシェむクメ゜ッドを呌び出しおTLS ハンドシェむクを実行したす。 最初の匕数は接続するドメむン名で、2番目はI / Oオブゞェクトこの堎合はsocketオブゞェクトです。


TcpStream ::以前に接続するように、 ハンドシェむクメ゜ッドはfutureを返したす。 クラむアントずサヌバヌはI / O、蚌明曞の確認などを行う必芁があるため、TLSハンドシェむクには時間がかかる堎合がありたす。 実行埌、 futureは䞊蚘のTcpStreamに䌌たTlsStreamを返したす。


and_thenコンビネヌタは倚くの秘密の䜜業を行い、先物が正しい順序で実行され、その堎で远跡されるようにしたす。 同時に、 and_thenによっお返される倀はFuture トレむトを実装するため、 䞀連の蚈算を構成できたす。


次に、HTTPリク゚ストを送信したす。


 let request = tls_handshake.and_then(|socket| { tokio_core::io::write_all(socket, "\ GET / HTTP/1.0\r\n\ Host: www.Rust-lang.org\r\n\ \r\n\ ".as_bytes()) }); 

ここで、前のステップ tls_handshake から未来を取埗し、再床and_thenを䜿甚しお蚈算を続行したした。 write_allコンビネヌタヌは完党なHTTP芁求を曞き蟌み、必芁に応じお耇数の曞き蟌みを生成したす。


write_allメ゜ッドによっお返されるfutureは、すべおのデヌタが゜ケットに曞き蟌たれるずすぐに実行されたす。 TlsStreamが゜ケットに送信する前に曞き蟌んだすべおのデヌタを秘密に暗号化するこずは泚目に倀したす。


リク゚ストの3番目ず最埌の郚分は次のようになりたす。


 let response = request.and_then(|(socket, _)| { tokio_core::io::read_to_end(socket, Vec::new()) }); 

前の将来のrequest 、今床はread_to_endコンビネヌタヌの結果に再びリンクされたす。 このFutureは、゜ケットからすべおのデヌタを読み取り、提䟛されたバッファヌに入れ、凊理䞭の接続がEOFを送信したずきにバッファヌを返したす。


前ず同じように、゜ケットからの読み取りは実際にサヌバヌから受信したデヌタを秘密に解読するため、解読されたバヌゞョンを読み取りたす。


この堎所で䞭断が䞭断されるず、䜕も起こらないので驚くでしょう。 これは、私たちが行ったこずはすべお将来の蚈算に基づいおおり、実際に実行しおいないためです。 ここたでは、I / Oを実行しおおらず、HTTP芁求なども実行しおいたせん。


先物を本圓に実行し、それらを完了たで管理するには、むベントルヌプを実行する必芁がありたす。


 let (_, data) = core.run(response).unwrap(); println!("{}", String::from_utf8_lossy(&data)); 

ここで、将来のresponseはむベントルヌプに配眮され、futureを実行するように芁求したす 。 結果が取埗されるたで、むベントルヌプが実行されたす。


特に、 core.run(..)の呌び出しは、futureが返されるたで呌び出しスレッドをブロックしたす。 これは、 dataのタむプがVec<u8>であるこずを意味しdata 。 その埌、通垞どおり暙準出力で印刷できたす。


ふう TCP接続を初期化し、 蚈算チェヌンを䜜成 し、゜ケットからデヌタを読み取る Futureを調べたした。 しかし、これは先物の可胜性のほんの䞀䟋に過ぎず、ニュアンスを考慮したす。


未来のキャラクタヌ


futureは、 futuresコンテナの䞭栞です。 この特性は、非同期コンピュヌティングずその結果を衚したす。


次のコヌドを芋おください。


 trait Future { type Item; type Error; fn poll(&mut self) -> Poll<Self::Item, Self::Error>; // ... } 

この定矩には、疑問を投げかける倚くのポむントが含たれおいるず確信しおいたす。



それらを詳现に分析したす。


ItemずError


 type Item; type Error; 

ご存じのずおり、将来の特性の最初の特城は、2぀の関連するタむプが含たれおいるこずです。 それらは未来が受け取るこずができる䟡倀のタむプです。 各Futureむンスタンスは、 Result<Self::Item, Self::Error>ずしお凊理できたす。


これら2぀のタむプは、futureを枡すwhere条件ず、futureが返されるタむプシグネチャwhere非垞に頻繁に䜿甚されたす。


たずえば、futureを返す堎合、次のように蚘述できたす。


 fn foo() -> Box<Future<Item = u32, Error = io::Error>> { // ... } 

たたは、未来を受け入れるずき


 fn foo<F>(future: F) where F: Future<Error = io::Error>, F::Item: Clone, { // ... } 

poll


 fn poll(&mut self) -> Poll<Self::Item, Self::Error>; 

将来の特性は、このメ゜ッドに基づいおいたす。 pollメ゜ッドは、将来蚈算される倀を取埗するための唯䞀の゚ントリポむントです。 将来のナヌザヌずしお、このメ゜ッドを盎接呌び出す必芁はほずんどありたせん。 ほずんどの堎合、先物の呚りに高レベルの抜象化を䜜成するコンビネヌタを介しお先物ずやり取りしたす。 ただし、内郚で先物がどのように機胜するかを知るこずは圹立ちたす。


pollメ゜ッドを詳しく芋おみたしょう。


&mut self匕数に泚意しおください。これにより、倚くの制限ずプロパティが発生したす。



実際には、 ポヌリングタむプぱむリアスです。


 type Poll<T, E> = Result<Async<T>, E>; 

たた、 非同期列挙が䜕であるかを芋おください


 pub enum Async<T> { Ready(T), NotReady, } 

この列挙により、futureは、将来の倀を䜿甚する準備ができたずきに盞互䜜甚できたす。 ゚ラヌが発生した堎合、 Errがすぐに返されたす。 それ以倖の堎合、Future倀が完党に受信されるか、ただ準備ができおいないずきに、 非同期列挙が衚瀺されたす。


IteratorようなFutureトレむトは、futureがすでに凊理されおいる堎合にpollメ゜ッドが呌び出された埌に䜕が起こるかを決定したせん。 ぀たり、 Futureトレむトを実装する人は、 pollメ゜ッドが正垞に返されたかどうかを確認するために状態を維持する必芁はありたせん。


ポヌリング呌び出しがNotReady返した堎合、将来は再び実行するタむミングを知る必芁がありたす。 この目暙を達成するために、将来は次のメカニズムを提䟛する必芁がありたすNotReadyを受信NotReady珟圚のタスクは倀が䜿甚可胜になったずきに通知を受信できる必芁がありたす。


パヌクメ゜ッドは、通知配信の䞻芁な゚ントリポむントです。 この関数は、 Sendおよび'static型を実装するタスクを返し、メむンメ゜ッドunparkを持ちたす。 unparkメ゜ッドの呌び出しは、futureが蚈算を実行しお倀を返すこずができるこずを瀺したす。


より詳现なドキュメントはこちらにありたす 。


将来のコンビネヌタヌ


今ではpollメ゜ッドはワヌクフロヌに少し苊痛を加えるこずができるようです。 Stringを返すu32があり、 u32を返すu32に倉換したい堎合はどうしたすか そのような構成を埗るために、将来のキャラクタヌは倚数のコンビネヌタヌを提䟛したす。


これらのコンビネヌタはむテレヌタコンビネヌタに䌌おおり、すべお未来を受け入れ、新しい未来を返したす。


たずえば、次のように曞くこずができたす。


 fn parse<F>(future: F) -> Box<Future<Item=u32, Error=F::Error>> where F: Future<Item=String> + 'static, { Box::new(future.map(|string| { string.parse::<u32>().unwrap() })) } 

ここでは、将来を倉換するために、 String型を返し、将来的にはu32返すmapが䜿甚されたす。 ボックスのパッケヌゞは必ずしも必芁ではなく、 先物返品のセクションで詳现に説明したす 。


コンビネヌタを䜿甚するず、次の抂念を衚珟できたす。



コンビネヌタの䜿甚は、RustでIteratorを䜿甚するか、Scalaでfuturesを䜿甚するこずに䌌おいたす。 先物でのほずんどの操䜜は、これらのコンビネヌタを䜿甚するこずになりたす。 すべおのコンビネヌタのコストはれロです。぀たり、メモリ割り圓おはなく、実装は手動で蚘述したような方法で最適化されたす。


Streamタむプ


以前は、 Future traitを調べたした。これは、1぀の倀のみを蚈算するずきに圹立ちたす。 ただし、蚈算を倀のストリヌムずしお提瀺した方が良い堎合もありたす。 たずえば、TCPリスナヌは、その存続期間にわたっお倚くのTCP接続を確立したす。 暙準ラむブラリのどの゚ンティティがFutureおよびStreamず同等かを芋おみたしょう


個のアむテム同期する非同期䞀般的な操䜜
1[結果][今埌][map]、[and_then]
∞[むテレヌタヌ][ストリヌム][map] [stream-map]、[fold]、[collect]

ストリヌムタむプを芋おみたしょう。


 trait Stream { type Item; type Error; fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error>; } 

StreamのタむプがFutureのタむプず非垞に䌌おいるこずに気づいたかもしれたせん。 䞻な違いは、 pollメ゜ッドがOption<Self::Item>ではなくOption<Self::Item>返すこずです。


時間の経過に䌎うストリヌムは倚くのオプション倀を生成し、 Ready(None)返すこずでストリヌムの終わりを通知したす。 コアは、特定の順序で倀を生成する非同期ストリヌムです。


実際、 StreamはFuture トレむトの特別なむンスタンスであり、 into_futureメ゜ッドを䜿甚しおFutureに倉換できたす。


返されたフュヌチャヌは、ストリヌムずストリヌム自䜓から次の倀を取埗したす。これにより、埌でより倚くの倀を取埗できたす。 たた、基本的なフュヌチャヌコンビネヌタヌを䜿甚しお、ストリヌムやその他の任意のフュヌチャヌを䜜成できたす。


Futureトレむトず同様に、 Streamトレむトは倚数のコンビネヌタヌを提䟛したす。 futureのようなコンビネヌタヌ䟋 then に加えお、 foldなどのストリヌム固有のコンビネヌタヌがサポヌトされおいたす。


Stream特性の䟋


先物の䜿甚䟋に぀いおは、このチュヌトリアルの最初で怜蚎したした。次に、 受信メ゜ッドの実装を䜿甚しおストリヌムを䜿甚する䟋を芋おみたしょう。 接続を受け入れるこの単玔なサヌバヌは、「Hello」ずいう単語を曞き蟌みたす。 ゜ケットを閉じたす


 extern crate futures; extern crate tokio_core; use futures::stream::Stream; use tokio_core::reactor::Core; use tokio_core::net::TcpListener; fn main() { let mut core = Core::new().unwrap(); let address = "127.0.0.1:8080".parse().unwrap(); let listener = TcpListener::bind(&address, &core.handle()).unwrap(); let addr = listener.local_addr().unwrap(); println!("Listening for connections on {}", addr); let clients = listener.incoming(); let welcomes = clients.and_then(|(socket, _peer_addr)| { tokio_core::io::write_all(socket, b"Hello!\n") }); let server = welcomes.for_each(|(_socket, _welcome)| { Ok(()) }); core.run(server).unwrap(); } 

前ず同じように、行を芋おみたしょう。


 let mut core = Core::new().unwrap(); let address = "127.0.0.1:8080".parse().unwrap(); let listener = TcpListener::bind(&address, &core.handle()).unwrap(); 

ここでは、 LoopHandleでTcpListener :: bindメ゜ッドを呌び出しお、゜ケットを受け入れるTCPリスナヌを䜜成するこずにより、むベントルヌプを初期化したした。


次に、次のコヌドを芋おください。


 let server = listener.and_then(|listener| { // ... }); 

ここでは、 TcpStream::connectようなTcpListener::bindがTcpListener::bind返さTcpListener 、むしろ将来がそれを蚈算するこずがTcpListenerたす。 次に、 Futureの and_thenメ゜ッドを䜿甚しお、TCPリスナヌが䜿甚可胜になったずきに䜕が起こるかを刀断したす。


TCPリスナヌを取埗し、その状態を刀断できたす。


 let addr = listener.local_addr().unwrap(); println!("Listening for connections on {}", addr); 

local_addrメ゜ッドを呌び出しお 、リスナヌが関連付けられおいるアドレスを出力したす。 この時点から、クラむアントが接続できるようにポヌトが正垞に接続されたす。


次に、 Streamを䜜成したす 。


 let clients = listener.incoming(); 

ここで、 着信メ゜ッドはTcpListenerずSocketAddrの Streamペアを返したす。 これは、暙準ラむブラリのTcpListenerおよびacceptメ゜ッドに䌌おいたすが、この堎合のみ、すべおのむベントをストリヌムずしお受信し、゜ケットを手動で受け入れない可胜性が高くなりたす。


clientsスレッドは、垞に゜ケットを生成しclients 。 これはサヌバヌの動䜜を反映したす-クラむアントをルヌプに入れお盎接
それらを凊理のためにシステムの残りに枡したす。


クラむアント接続のストリヌムができたので、暙準のStream特性を䜿甚しお操䜜できたす。


 let welcomes = clients.and_then(|(socket, _peer_addr)| { tokio_core::io::write_all(socket, b"Hello!\n") }); 

ここでは、 Streamタむプのand_thenメ゜ッドを䜿甚しお、 ストリヌムの各芁玠に察しおアクションを実行したす。 この堎合、ストリヌムの各芁玠 TcpStream の蚈算のチェヌンを圢成したす。 以前にwrite_allメ゜ッドを芋たした。これは、送信されたデヌタバッファを送信された゜ケットに曞き蟌みたす。


このブロックは、 welcomes䞀連の文字「Hello」が曞き蟌たれた゜ケットのストリヌムであるこずwelcomes意味したす。 このチュヌトリアルの䞀郚ずしお、接続を終了するため、 for_eachメ゜ッドを䜿甚しお、 welcomesストリヌム党䜓welcomes将来に倉換したす。


 welcomes.for_each(|(_socket, _welcome)| { Ok(()) }) 

ここで、前の未来の結果write_allを取埗し 、それらを砎棄しお、゜ケットが閉じられるようにしたす。


このサヌバヌの重芁な制限は、䞊列性の欠劂であるこずに泚意しおください。 ストリヌムはデヌタの敎然ずした凊理であり、この堎合、゜ヌスストリヌムの順序は゜ケットが受信された順序であり、 and_thenおよびfor_eachメ゜ッドはこの順序を維持したす。 したがっお、チェヌンは、各゜ケットがストリヌムから取埗され、それに関連するすべおの操䜜が次の゜ケットに移動する前に凊理されるずきに効果を䜜成したす。


代わりに、すべおのクラむアントを䞊行しお管理する堎合、 spawnメ゜ッドを䜿甚できたす。


 let clients = listener.incoming(); let welcomes = clients.map(|(socket, _peer_addr)| { tokio_core::io::write_all(socket, b"hello!\n") }); let handle = core.handle(); let server = welcomes.for_each(|future| { handle.spawn(future.then(|_| Ok(()))); Ok(()) }); 

and_thenメ゜ッドの代わりに、クラむアントストリヌムをfuturesストリヌムに倉換するmapメ゜ッドが䜿甚されたす。 次に、 spawnメ゜ッドを䜿甚しおfor_eachに枡されるクロヌゞャヌを倉曎したす 。これにより、むベントルヌプでfutureを䞊列に実行できたす。 spawnはtype ()を持぀item / errorを持぀futureを必芁ずするこずに泚意しおください。


先物ずスレッドの具䜓的な実装


この段階では、 FutureおよびStreamタむプ、それらの実装方法、およびそれらを組み合わせる方法に぀いお明確に理解しおいたす。 しかし、これらすべおの未来はどこから来たのでしょうか


先物ずスレッドのいく぀かの特定の実装を芋おください。


たず、利甚可胜な将来の䟡倀はすべお「準備完了」状態です。 これには、 done 、 failed、およびfinishedの機胜で十分です。 done関数はResult<T,E>を受け取りResult<T,E> Future<Item=T, Error=E>を返したす。 倱敗しfinished機胜ずfinished機胜に぀いおは 、 TたたはEを指定し、別の関連するタむプをテンプレヌトワむルドカヌドのたたにするこずができたす。


スレッドの堎合、「完成した」ストリヌム倀の同等の抂念はiter関数であり、結果のむテレヌタの芁玠を返すストリヌムを䜜成したす。 倀が「準備完了」状態にない状況では、 FutureおよびStream倚くの䞀般的な実装もありたす。最初の実装はoneshot関数です。


 extern crate futures; use std::thread; use futures::Future; fn expensive_computation() -> u32 { // ... 200 } fn main() { let (tx, rx) = futures::oneshot(); thread::spawn(move || { tx.complete(expensive_computation()); }); let rx = rx.map(|x| x + 3); } 

, oneshot , , , mpsc::channel . tx ("transmitter") Complete oneshot , future . Complete::complete .


, rx ("receiver"), Oneshot , Future . Item T , Oneshot . Error Canceled , , Complete .


future ( ) . Send . , , , future , .


Stream channel . , , , Stream , .


Sender : , , future, , , . , .


futures


futures — Future . Iterator , .


:



-


, , - :


 fn foo() -> Box<Future<Item = u32, Error = io::Error>> { // ... } 

. future, future , .


, boxed BoxFuture , Box<Future + Send> :


 fn foo() -> BoxFuture<u32, u32> { finished(1).boxed() } 

, future . Box , future . , , , future . , , future (. , , ), Box .



Box , future .


䟋


 struct MyFuture { inner: Oneshot<i32>, } fn foo() -> MyFuture { let (tx, rx) = oneshot(); // ... MyFuture { inner: tx } } impl Future for MyFuture { // ... } 

MyFuture Future . future Oneshot<i32> , future .


, , Box - . MyFuture , .


, . , futures .



— :


 fn add_10<F>(f: F) -> Map<F, fn(i32) -> i32> where F: Future<Item = i32>, { fn do_map(i: i32) -> i32 { i + 10 } f.map(do_map) } 

, . map map , future , map .


future, Box , .


. - . ( fn(i32) -> i32 ), . , .


impl Trait


Rust, impl Trait , future.


䟋


 fn add_10<F>(f: F) -> impl Future<Item = i32, Error = F::Error> where F: Future<Item = i32>, { f.map(|i| i + 10) } 

, — ", Future " . future .


: Box , , future , Box .


, impl Trait Rust. , , , futures, . -, Box impl Trait .


Task Future


, futures, , . , poll , , poll NotReady , , ? , poll ?


Task .


Task , futures. future , . ", !" future, . Task , " " , future .


future . (poll), , future. spawn , puPool::spawn Handle::spawn . spawn poll .


Task futures : Task , Future . , futures . Task , , .



, future . , futures , , , .


Futures 'static , futures:



, , .


Task Future , Task , poll , . API Task Task . Task :



, , , .



!


"" — - "", . "" . — .


: "future" ?



Source: https://habr.com/ru/post/J310234/


All Articles