C言語が最高のファイルAPIを持つ理由
本文の状態
日本語全文を表示中
詳細モードで約5分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
Andrej Karpathy 厳選
C言語は、ファイルをメモリ内のデータと同様に直接アクセスできるAPIを提供しており、多くのプログラミング言語がファイル操作を後回しにしている中で優位性を示している。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
優れたプログラミング言語は数多くありますが、ファイル操作は常に後回しにされているように思えます。
通常はread()、write()、そして何らかのシリアライゼーションライブラリしか提供されません。
C言語では、メモリ内のデータと全く同じ方法でファイルにアクセスできます:
/* HTMLタグ、キーワード、コマンド */
h-n {color: #F27;}
/* 値 */
h-v {color: #B8F;}
/* CSSセレクタ、属性/変数名、ファイル名 */
h-s {color: #AEE;}
/* コメント */
h-c {color: #777;}
h-e {color: #F6F;}
#include
#include
#include
#include
#include
void main() {
// 1000個の符号なし整数を含むファイルを作成/開く
// 全てゼロで初期化
int len = 1000 * sizeof(uint32_t);
int file = open("numbers.u32", O_RDWR | O_CREAT, 0600);
ftruncate(file, len);
// メモリにマップする
uint32_t* numbers = mmap(NULL, len,
PROT_READ | PROT_WRITE, MAP_SHARED,
file, 0);
// 何か処理を行う:
printf("%d\n", numbers[42]);
numbers[42] = numbers[42] + 1;
// クリーンアップ
munmap(numbers, len);
close(file);
}
メモリマッピングは、ファイルをメモリに読み込むこととは同じではありません。
ファイルがRAMに収まらない場合でも機能します。
データは必要に応じて読み込まれるため、テラバイト級のファイルを開くのに一日かかることはありません。
これは全てのデータ型で機能し、自動的にキャッシュされます。
このキャッシュは、システムが他の目的でメモリを必要とする場合、自動的にクリアされます。
しかし、他のほとんどの言語では、
小さな塊でread()し、パースし、処理し、シリアライズし、最終的にwrite()でディスクに書き戻さなければなりません。
これは機能しますが、遅く、不必要にシーケンシャルアクセスに制限されています。
コンピュータは何十年もテープを使っていないのです。
もし幸運にもメモリマッピングが利用できたとしても、バイト配列に制限されるでしょう。
それでも明示的なパース/シリアライズが必要です。
結局はread()とwrite()を呼び出す、より洗練された方法に過ぎません。
ほとんどの言語がすでにカスタムアロケータをサポートしていることを考えると、ファイルにアクセスするより良い方法を追加することは十分に実現可能に思えます...
しかし、私の知る限り、C言語はバイナリフォーマットを指定してそのまま使用できる唯一の言語です。
C言語の実装はそれほど優れているわけでもありません。
メモリマッピングにはある程度のオーバーヘッド(ページフォルト、TLBフラッシュ)があり、C言語はエンディアンを処理するための何も行いません——
しかし、何もないよりはましです。
確かに、何らかのパースやバリデーションを行いたいかもしれませんが、これはデータがディスクから読み出されるたびに必要とされるべきではありません。
大きなデータを扱う場合、メモリ不足になることは非常に一般的で、全てをRAMにパースすることは不可能になります。
コードを複雑にすることなく、単にデータをオフロードできることは非常に便利です。
Pythonのpickleを見てください。
それは完全に安全でないシリアライゼーション形式です。
ファイルをロードすると、単にいくつかの数値が欲しいだけなのに、コード実行が引き起こされる可能性があります...
それでも、Pythonのコードとデータを混在させるモデルに合っているため、非常に広く使われています。
多くのファイルは、信頼できない外部ソースからのものではありません。
ファイル操作も同様に軽視されています。
ファイルシステムはオリジナルのNoSQLデータベースですが、C言語のreaddir()のラッパー以上のものを得ることはほとんどありません。
これは通常、ファイルシステムの上にSQLiteのような別のデータベースを実行する結果になります。
しかし、リレーショナルデータベースは決してプログラムに完全に適合しません。
...そしてSQLはファイルよりもさらに統合が悪いです。
全てのデータをシリアライズしなければならないことに加えて、アクセスするためだけに全く別の言語でコードを書かなければなりません!
ほとんどのプログラマは単にキーバリューストアとして使用し、独自のメタデータ処理を実装します。
奇妙な三重にネストしたデータベースを作成することになるのです。
だからタイトルに答えるために、
私はこれは悪い前提の結果だと思います。
ファイルから読み取られるデータはどこか別の場所から来ていて、パースする必要があるという前提...
そしてディスクに書き込まれるデータはどこかに送られていて、標準フォーマットにシリアライズする必要があるという前提。
これはメモリ制約のあるシステムでは単純に真実ではありません——
そして100GBのファイルを扱う場合——
あらゆるシステムがメモリ制約を受けるのです。
原文を表示
There are a lot of nice programming languages, but files always seem like an afterthought.
You usually only get read(), write() and some kind of serialization library.
In C, you can access files exactly the same as data in memory:
/* HTML tags, keywords, commands */
h-n {color: #F27;}
/* Values */
h-v {color: #B8F;}
/* CSS selectors, attribute/varable names, file names */
h-s {color: #AEE;}
/* Comments */
h-c {color: #777;}
h-e {color: #F6F;}
#include
#include
#include
#include
#include
void main() {
// Create/open a file containing 1000 unsigned integers
// Initialized to all zeros.
int len = 1000 * sizeof(uint32_t);
int file = open("numbers.u32", O_RDWR | O_CREAT, 0600);
ftruncate(file, len);
// Map it into memory.
uint32_t* numbers = mmap(NULL, len,
PROT_READ | PROT_WRITE, MAP_SHARED,
file, 0);
// Do something:
printf("%d\n", numbers[42]);
numbers[42] = numbers[42] + 1;
// Clean up
munmap(numbers, len);
close(file);
}
Memory mapping isn't the same as loading a file into memory:
It still works if the file doesn't fit in RAM.
Data is loaded as needed, so it won't take all day to open a terabyte file.
It works with all datatypes and is automatically cached.
This cache is cleared automatically if the system needs memory for something else.
However, in other most languages,
you have to read() in tiny chunks, parse, process, serialize and finally write() it back to the disk.
This works, but is slow and needlessly limited to sequential access:
Computers haven't used tape for decades.
If you're lucky enough to have memory mapping, it will be limited to byte arrays,
which still require explicit parsing/serialization.
It ends up as just a nicer way to call read() and write()
Considering that most languages already support custom allocators, adding a better way to access files seems very doable...
but, as far as I'm aware, C is the only language that lets you specify a binary format and just use it.
C's implemenation isn't even very good:
Memory mapping comes some overhead (page faults, TLB flushes) and C does nothing to handle endianness —
but it doesn't take much to beat nothing.
Sure, you might want to do some parsing and validation, but this shouldn't be required every time data leaves the disk.
When working with larger data, it's very common to run out of memory, making it impossible to just parse everything into RAM.
Being able to just offload data without complicating the code is very useful.
Just look at Python's pickle:
it's a completely insecure serialization format.
Loading a file can cause code execution even if you just wanted some numbers...
but still very widely used because it fits with the mix-code-and-data model of python.
A lot of files are not untrusted.
File manipulation is similarly neglected.
The filesystem is the original NoSQL database, but you seldom get more then a wrapper around C's readdir().
This usually results in people running another database, such as SQLite, on top of the filesystem,
but relational databases never quite fit your program.
... and SQL integrates even worse than files:
On top of having to serialize all your data, you have to write code in a whole separate language just to access it!
Most programmers just use it as a key-value store, and implement their own metadata handling:
creating a bizarre triple nested database.
So to answer the title,
I think it's a result of a bad assumption:
That data being read from a file is coming from somewhere else and needs to be parsed...
and that data being written to disk is being sent somewhere and needs to be serialized into a standard format.
This simply isn't true on memory constrained systems —
and with 100 GB files —
every system is memory constrained.
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み