**TTYとバッファリング**

2026/01/18 2:01

**TTYとバッファリング**

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

Rust の標準出力は、C と異なり常に 行バッファリング を使用するため、出力がパイプで接続されたりリダイレクトされた場合でも同様です。対照的に C プログラムは端末外ではブロック(フル)バッファリングに切り替わるため、数キロバイト分のデータが蓄積してから表示されることがあり、パイプラインで顕著な遅延を引き起こします。Rust の

print!
マクロは
LineWriter
を通じて書き込みを行い、環境に関係なく各行が即座にフラッシュされます。開発者が明示的に制御したい場合は、
io::stdout().flush()
を呼び出して出力を強制的にフラッシュできます。

標準ライブラリでは現在

Stdout
FIXME コメント付きで実装されており、標準出力が端末に接続されているかどうか(
IsTerminal::is_terminal()
)に応じて
LineWriter
BufWriter
のどちらを選択するべきだと示されています。Ripgrep などのツールはすでに TTY 検出を利用して色付けやバッファリングを切り替えており、対話型端末には行バッファリング付き出力を、非TTY環境にはブロックバッファリング付き出力を選択します。

Rust の

Stdout
が常に行バッファリングをデフォルトとするため、Rust プログラムはコマンドラインセッションと自動化ワークフローの両方で一貫した予測可能な出力を示します。これにより、パイプやリダイレクト時に C のフルバッファリングが引き起こす遅延や不意な挙動と比べてデバッグが簡素化され、驚きが減少します。

本文

標準出力は実際にいつフラッシュされるのか?
開発者なら誰もが「バッファがフラッシュされるまで表示されない」プログラムを見たことがあるだろう。代表的な StackOverflow の回答は バッファをフラッシュしなければならない というものだ。以下ではその理由と、Rust が C とどう違うのかを解説する。


簡単な C の例

#include <stdio.h>
#include <unistd.h>

int main() {
    for (int i = 1; i <= 5; i++) {
        printf("line %d\n", i);
        sleep(1);
    }
    return 0;
}

ターミナルで実行すると:

$ gcc -o cprint cprint.c
$ ./cprint
line 1   ← t=1 に表示
line 2   ← t=2 に表示
…

パイプに出力を渡すと状況が変わる:

$ ./cprint | cat
            ← 5 秒間何も表示されない …
line 1   ← t=5 に表示
…

なぜ?

printf()
バッファ に書き込む。TTY(対話型端末)では libc が 行バッファリング を使用し、
\n
を見たら自動でフラッシュされる。一方、パイプやファイルなどの非 TTY ではデフォルトで 完全バッファリング(約 4–8 KB)になるため、出力全体がバッファに溜まってからしか表示されない。

stderr
は特殊で、通常は未バッファ化または行バッファ化されるので、パイプ経由でもエラーメッセージはすぐに表示される。


Rust – 同じ話だが実装は違う

use std::io::{self, Write};
use std::thread::sleep;
use std::time::Duration;

fn main() {
    print!("Hello");
    sleep(Duration::from_secs(3));
    println!(" World!");
}

実行すると:

$ cargo run
            ← 3 秒間何も表示されない …
Hello World!

パイプでも同様:

$ cargo run | cat
            ← 3 秒間何も表示されない …
Hello World!

Rust の

print!
マクロは行バッファリングを使っているため、最初の
print!
は次に来る
println!
が出るまでフラッシュされない。明示的にフラッシュしたい場合は:

fn main() {
    print!("Hello");
    io::stdout().flush().unwrap();
    sleep(Duration::from_secs(3));
    println!(" World!");
}

これで得られる出力は:

$ cargo run
Hello            ← t=0
Hello World!     ← t=3

パイプ経由でも同じ結果になる。


TTY の検知

Rust は

std::io::IsTerminal
を介して
is_terminal()
を提供する:

use std::io::{self, IsTerminal};

fn main() {
    if io::stdout().is_terminal() {
        println!("TTY!");
    } else {
        println!("NOT TTY!");
    }
}

実行結果は以下のようになる。

実行結果
cargo run
TTY!
`cargo runcat`
cargo run > out && cat out
NOT TTY!

実際のユースケース – ripgrep

let printer = StandardBuilder::new()
    .color_specs(ColorSpecs::default_with_color())
    .build(cli::stdout(if std::io::stdout().is_terminal() {
        ColorChoice::Auto   // 端末ならカラーを有効化
    } else {
        ColorChoice::Never  // ANSI コードを除去
    }));

ripgrep
is_terminal()
を使って、色付き出力かどうかを判断する。内部の書き込み先は TTY の場合行バッファリング、パイプの場合ブロックバッファリングになるため、両者のメリットを活かせる。


Rust の stdout が異なる理由

C とは違い、Rust の標準ライブラリは現在 常に

stdout
を行バッファリング にしている。ソースコードでは次のようになっている:

pub struct Stdout {
    inner: &'static ReentrantLock<RefCell<LineWriter<StdoutRaw>>>,
}

コメントには「理想的にはターミナルに接続されていないときは

BufWriter
に切り替えるべきだが、まだ優先度が高くない」とある。


TL;DR

環境C の stdout (libc)Rust の stdout
TTY行バッファリング行バッファリング
非 TTY完全バッファリング行バッファリング
  • C では非 TTY 出力はバッファが埋まるかプログラムが終了するまで遅延する。
  • Rust では
    stdout
    は常に改行でフラッシュされる(手動で
    flush()
    を呼ばない限り)。
  • is_terminal()
    を使って対話型とパイプ/リダイレクトされた出力を区別し、カラーやバッファリングの挙動を調整できる。

さらに読む

同じ日のほかのニュース

一覧に戻る →

2026/01/23 0:20

**GPTZero、NeurIPS 2025受理論文で新たに100件の幻覚現象を発見**

2026/01/18 8:29

**Scheme を WebAssembly にコンパイル**

## Japanese Translation: --- ## Summary Pythonで実装されたオープンソースScheme実装「Bob」は、15周年を記念してネイティブWASMバイナリを生成するWebAssembly(WASM)コンパイラを追加しました。新しい `WasmCompiler` は解析済みのScheme式を直接WASMテキストに変換し、その後 wasm‑tools スイートでコンパイルされ、Node.js経由で実行されます。 コンパイラの核心は、Schemeプリミティブを実装する約1,000行のWASMコードから成ります: - **オブジェクト表現** – SchemeオブジェクトはWASM GC型にマッピングされます: - `$PAIR` 構造体は `car` と `cdr` を `(ref null eq)` 参照として保持します。 - `$BOOL` 構造体は単一の `i32`(0 = false、非ゼロ = true)を保持します。 - `$SYMBOL` 構造体は線形メモリ内でオフセットと長さを表す2つの `i32` を保存します。 - **数値** – 整数値は `i31` 型を使用してボックス化されていない整数を直接参照します。 - **シンボル** – シンボルは線形メモリに固定オフセット(例: `(data (i32.const 2048) "foo")`)で発行され、アドレス/長さペアで参照されます。 - **組み込み関数** – `write` 関数はWASMテキスト内で直接実装され、ホスト関数として `write_char` と `write_i32` の2つだけをインポートします。 Bobはすでにインタープリタ、コンパイラ、VM、およびカスタムマーク・アンド・スウィープGCを備えたC++ VMを提供しています。追加されたコンパイラは今後さらに進化する予定ですが、現在のwasmtime用Pythonバインディングは2023年10月に仕様に組み込まれたWASM GC提案をまだサポートしていないため、SchemeをWebAssembly上で完全にガベージコレクション実行することが制限されています。 それでもユーザーは今やSchemeを直接WebAssemblyとして実行できるようになり、クロスプラットフォームのデプロイメントとJavaScript/Node.js環境とのより緊密な統合の可能性が開かれます。

2026/01/23 2:41

**CSS の光学的錯覚**

## Japanese Translation: (すべての主要なポイントを統合したもの) > 記事は、マウスホバーに応じて反応するインタラクティブな CSS ベースの錯視デモの CodePen ギャラリーを提示しています。 > 各デモは、Poggendorff の歪んだ線(傾いた 2 つのグラデーションと `::before`/`::after` を使用)、誘導グラデーション効果、Cornsweet & White の色コントラストトリック(黒白格子に `mix-blend-mode` を適用)、リングおよびチェッカーボードパターン、重なり合う線の色球体、曲率盲点、Café Wall イルлю(3 本のグラデーションで平行線を斜めにする)、ペノース三角形やエビングハウス円、カニッツァ四角形など、古典的な視覚現象を示しています。 > ギャラリーには、エビングハウス錯視のアニメーション版、回転する「タワー」、色のファン、逆スピーク、モーションバインディング、メンツラインズ、ウォッリングカラーなども含まれ、ドット線の動きやコントラスト非同期、息を吸う四角形、トロックラー消失といった静的に動きを示唆するパターンも掲載されています。 > すべての効果は CSS グラデーション、疑似要素、`mix-blend-mode`、およびキーフレームアニメーションで実現され、微妙な背景やホバー変更がどれほど印象的な視覚トリックを生み出せるかを示しています。 > コレクションは Patrick Pester の「35 optical…」リストと Michael Bach の「154 Visual Phenomena & Optical Illusions」に触発されています。 > Medium と DEV に公開されており、著者は将来の追加や改良の可能性について読者にコメントを残すよう呼びかけています。 *この改訂された要約は、すべての主要なポイントを完全に反映し、推測を加えず、明確で簡潔に保っています。*