関連記事
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。
標準入力からパイプで流したデータをキャンセル可能にしたいなーって思って、ライブラリ探してたら以下を発見。
Linuxの場合は、内部で epoll を使って制御してくれているみたいですね。ちょっと試してみました。
以下、サンプルです。
サンプル
package main import ( "errors""fmt""log""os""time""github.com/muesli/cancelreader" ) func main() { log.SetFlags(log.Lmicroseconds) log.SetOutput(os.Stdout) if err := run(); err != nil { log.Panic(err) } } func run() error { //// 標準入力をキャンセル可能なReaderにする//// cancelreader.CancelReaderは、Linuxの場合// 内部で epoll を利用して制御を行っている。//// なので、非ブロッキングI/Oが可能なファイルディスクリプタに対してのみ// キャンセル可能となっている。非ブロッキングI/Oが可能なものは例えば以下のもの。// - ソケット// - パイプ// - FIFO//// 通常のファイルは非ブロッキングI/O可能なファイルディスクリプタでは無いことに注意。// 通常のファイルをepollで利用すると epoll_ctl() で EPERM が返ってくる。// 通常のファイルをキャンセル可能にしたい場合は io_uring などを検討する。//var ( reader cancelreader.CancelReader err error ) reader, err = cancelreader.NewReader(os.Stdin) if err != nil { return fmt.Errorf("cancelreader.NewReader() failed: %w", err) } defer reader.Close() //// 3秒後にキャンセル//gofunc() { time.Sleep(3 * time.Second) reader.Cancel() }() //// 500ms毎に1文字読み込み//var ( buf [1]byte ) for { clear(buf[:]) if _, err = reader.Read(buf[:]); err != nil { if errors.Is(err, cancelreader.ErrCanceled) { log.Println("CANCELED") break } return fmt.Errorf("reader.Read() failed: %w", err) } log.Print(string(buf[:])) time.Sleep(500 * time.Millisecond) } returnnil }
試してみます。
$ task task: [default]echo -n helloworld | go run main.go 15:09:24.486356 h 15:09:24.987136 e 15:09:25.487775 l 15:09:25.988534 l 15:09:26.489191 o 15:09:26.989851 w 15:09:27.490367 CANCELED
ちゃんと途中でキャンセルがかかっていますね。
参考情報
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。