中学英語811710 views
中学理科1630641 views
ヒストリア290598 views
英語613639 views
小学社会310485 views
世界の国564520 views
MathPython497343 views
小学理科719870 views
教育149510 views
LaTeX962153 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

flush() と fsync() の違い:本当にディスクに書き込まれたか

flush()fsync() は似ているようで全く異なる。この違いを理解していないと、「保存したはずのデータが消えた」という事態に遭遇する。

flush() と fsync() の決定的な違い

flush()

Python/C ライブラリのバッファからカーネルのバッファに転送する。ディスクには書き込まない

fsync()

カーネルのバッファからディスクに書き込む。この関数が返ったとき、データはディスク上にある

import os

f = open("important.txt", "w")
f.write("critical data")

f.flush()
# この時点: カーネルのバッファにある(ディスクにはない)

os.fsync(f.fileno())
# この時点: ディスクに書き込まれた

f.close()

なぜ flush() だけでは不十分か

flush() の後、データはカーネルに渡されるが、カーネルはすぐにディスクに書き込むとは限らない。

flush() 呼び出し

データがカーネルのページキャッシュに入る

カーネルが「いつか」ディスクに書き込む(数秒〜数十秒後)

電源断が起きると、ページキャッシュのデータは消える

Linux のデフォルトでは、dirty ページ(変更されたがディスクに書き込まれていないページ)は 30 秒ほど保持される。この間に電源が落ちるとデータは失われる。

fsync() の動作

fsync() はシステムコールであり、カーネルにディスク書き込みを「強制」する。

import os

def safe_write(path, content):
    """データ消失を防ぐ書き込み"""
    with open(path, "w") as f:
        f.write(content)
        f.flush()            # カーネルに渡す
        os.fsync(f.fileno()) # ディスクに書き込む

fsync() はブロッキング関数で、ディスク I/O が完了するまで返らない。そのため低速だが、戻り値を受け取った時点でデータの永続化が保証される。

fdatasync() との違い

fsync() はデータとメタデータ(ファイルサイズ、更新時刻など)の両方を同期する。fdatasync() はデータのみを同期し、メタデータはスキップする場合がある。

fsync()

データ + メタデータを同期。より安全だがやや遅い

fdatasync()

データを同期。メタデータは次回の fsync まで遅延する可能性がある。やや速い

import os

f = open("data.txt", "w")
f.write("content")
f.flush()

# どちらか選ぶ
os.fsync(f.fileno())      # データ + メタデータ
os.fdatasync(f.fileno())  # データのみ(Linux 専用)

ディレクトリの fsync

新しいファイルを作成した場合、ファイルだけでなくディレクトリの fsync も必要になる場合がある。

import os

def really_safe_write(path, content):
    """完全に安全な書き込み"""
    dir_path = os.path.dirname(path) or "."
    
    with open(path, "w") as f:
        f.write(content)
        f.flush()
        os.fsync(f.fileno())
    
    # ディレクトリエントリも同期
    dir_fd = os.open(dir_path, os.O_RDONLY | os.O_DIRECTORY)
    try:
        os.fsync(dir_fd)
    finally:
        os.close(dir_fd)

ディレクトリの fsync がないと、ファイルの内容は書き込まれていても、ディレクトリエントリ(ファイル名と inode の対応)が失われる可能性がある。

パフォーマンスへの影響

fsync() は高コストな操作だ。毎回呼び出すとパフォーマンスが大幅に低下する。

import os
import time

# fsync なし: 高速
start = time.time()
with open("test.txt", "w") as f:
    for i in range(10000):
        f.write(f"line {i}\n")
print(f"fsync なし: {time.time() - start:.3f}秒")

# 毎回 fsync: 非常に低速
start = time.time()
with open("test2.txt", "w") as f:
    for i in range(10000):
        f.write(f"line {i}\n")
        f.flush()
        os.fsync(f.fileno())
print(f"毎回 fsync: {time.time() - start:.3f}秒")

# 結果例:
# fsync なし: 0.015秒
# 毎回 fsync: 15.234秒(1000倍遅い)

実践的なガイドライン

fsync が必要なケース

金融取引、設定ファイルの保存、データベースのコミットなど、データ消失が許されない場合。

fsync が不要なケース

ログファイル、キャッシュ、再生成可能なデータなど、消失しても問題ないか再取得可能な場合。

バランスを取る

重要なチェックポイントでのみ fsync を呼び、通常の書き込みは OS に任せる。

sync コマンドとの関係

シェルの sync コマンドはシステム全体の dirty ページをディスクに書き込む。

# システム全体を同期
sync

# Python から呼ぶ場合
import os
os.sync()

ただし、特定のファイルだけを同期したい場合は fsync() を使うべきだ。sync() はシステム全体に影響するため重い。

まとめ

操作データの到達先用途
flush()カーネルバッファ他プロセスから見えるようにする
fsync()ディスク電源断でもデータを保証
fdatasync()ディスク(データのみ)やや高速な永続化

「ファイルを閉じれば安心」ではない。close() は暗黙的に flush() を呼ぶが、fsync() は呼ばない。重要なデータを扱うなら、明示的に fsync() を呼ぶ習慣をつけよう。