pythonの file.write と os.write の違い
python で file.writeで書き込むのと、os.writeで書き込むのってどう違うの?
私は、ファイルを開いて書き込むとき、ライブラリで file objectを渡す時があるから f = open() で呼び出して、それをos.writeに渡すのは f.fileno()しなきゃいけないから面倒だし、何気なく f.write()で書いてました。
ふと、sync writeで書き込む機会があって、あれ?なんかすごい遅いぞ?と気づいたのです。同じ条件でddなら速い。色々試して、os.write()で書いてみたら速いことがわかりました。
1MBのファイルデータを書き込んだら、50倍遅い。。こりゃひどい。asyncで書いても2倍遅い。
なんで?
pythonのソース(2.6 です。3.xは知らないです。)を読んでみると、file_writeは書き込みの時に fwrite(3)をサイズ1で呼び出してる! 1MBのファイル書くのに百万回 I/O叩いてたわけか、こりゃ、遅いわけだ。。
static PyObject * file_write(PyFileObject *f, PyObject *args) { char *s; Py_ssize_t n, n2; if (f->f_fp == NULL) return err_closed(); if (!PyArg_ParseTuple(args, f->f_binary ? "s#" : "t#", &s, &n)) return NULL; f->f_softspace = 0; Py_BEGIN_ALLOW_THREADS errno = 0; n2 = fwrite(s, 1, n, f->f_fp); Py_END_ALLOW_THREADS if (n2 != n) { PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); return NULL; } Py_INCREF(Py_None); return Py_None; }
かたや、os.write (posix_write)は普通にwrite(2)を読んでるっぽい。
static PyObject * posix_write(PyObject *self, PyObject *args) { int fd; Py_ssize_t size; char *buffer; if (!PyArg_ParseTuple(args, "is#:write", &fd, &buffer, &size)) return NULL; Py_BEGIN_ALLOW_THREADS size = write(fd, buffer, (size_t)size); Py_END_ALLOW_THREADS if (size < 0) return posix_error(); return PyInt_FromSsize_t(size); }
と、いうことで、f.write()を使うべき理由がよくわからん。とりあえず os.write()つかっとこっと。