キャンセル

Future をドロップすると、その Future を再度ポーリングすることはできません。これはキャンセルと呼ばれ、どの await ポイントでも発生する可能性があります。そのため、Future がキャンセルされた場合でも、システムが正常に動作するようにしておく必要があります。たとえば、デッドロックやデータの消失があってはなりません。

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Speaker Notes

This slide should take about 18 minutes.
  • コンパイラではキャンセル安全性を確保できません。API ドキュメントを読み、async fn が保持する状態を考慮する必要があります。

  • panic?とは異なり、キャンセルは(エラー処理ではなく)通常の制御フローの一部です。

  • この例では、文字列の一部が失われています。

    • tick() 分岐が先に終了するたびに、next() とその buf がドロップされます。

    • buf を構造体の一部にすることで、LinesReader にキャンセル安全性を持たせることができます。

      #![allow(unused)] fn main() { struct LinesReader { stream: DuplexStream, bytes: Vec<u8>, buf: [u8; 1], } impl LinesReader { fn new(stream: DuplexStream) -> Self { Self { stream, bytes: Vec::new(), buf: [0] } } async fn next(&mut self) -> io::Result<Option<String>> { // buf と bytes の先頭に self を付加します。 // ... let raw = std::mem::take(&mut self.bytes); let s = String::from_utf8(raw) .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "not UTF-8"))?; // ... } } }
  • Interval::tick は、ティックが「配信済み」かどうかを追跡しているため、安全にキャンセルできます。

  • AsyncReadExt::read は、データを返すか、データを読み取らないかのいずれかであるため、安全にキャンセルできます。

  • AsyncBufReadExt::read_line はこの例と類似しており、安全にキャンセルできません。詳細と代替方法については、ドキュメントをご覧ください。