- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
在 Python 中,为什么是 os.lseek()
比 seek()
慢很多file-like objects 上的方法?
$ dd if=/dev/urandom of=test.bin bs=1024 count=1024
1024+0 records in
1024+0 records out
1048576 bytes transferred in 0.063247 secs (16579072 bytes/sec)
$ python -m timeit -s 'import os; f = open("test.bin", "r")' 'for i in xrange(10000): f.seek(i, os.SEEK_SET)'
100 loops, best of 3: 2.62 msec per loop
$ python -m timeit -s 'import os; f = os.open("test.bin", os.O_RDONLY)' 'for i in xrange(10000): os.lseek(f, i, os.SEEK_SET)'
100 loops, best of 3: 4.23 msec per loop
docs for os.open()
说“此函数用于低级 I/O”。我认为“低级 I/O”会更快。
我在配备固态硬盘的 MacBook Pro 上使用 Mac OS 10.10.5 上的 CPython 2.7.9。
最佳答案
低级别并不一定意味着更快。它只是意味着低级。鉴于 python 主要用于高级用途,因此高级 API 通常经过相当优化,并且避免了您必须处理编写“等效”低级代码的陷阱。
现在 os.open
返回一个 文件描述符,它是一个整数,这是系统调用实际传递的内容(这就是它被称为低级的原因. 你通常不想直接处理文件描述符并将其留给解释器。)
open
函数返回一个file
对象。可以找到seek方法的实现here它非常简单:它会进行一些错误检查,最后调用 _portable_fseek
:
Py_DECREF(off_index);
if (PyErr_Occurred())
return NULL;
FILE_BEGIN_ALLOW_THREADS(f)
errno = 0;
ret = _portable_fseek(f->f_fp, offset, whence);
FILE_END_ALLOW_THREADS(f)
if (ret != 0) {
PyErr_SetFromErrno(PyExc_IOError);
clearerr(f->f_fp);
return NULL;
}
f->f_skipnextlf = 0;
Py_INCREF(Py_None);
return Py_None;
定义_portable_fseek
的地方here它的实现是 真的只是:
static int
_portable_fseek(FILE *fp, Py_off_t offset, int whence)
{
#if !defined(HAVE_LARGEFILE_SUPPORT)
return fseek(fp, offset, whence);
#elif defined(HAVE_FSEEKO) && SIZEOF_OFF_T >= 8
return fseeko(fp, offset, whence);
#elif defined(HAVE_FSEEK64)
return fseek64(fp, offset, whence);
#elif defined(__BEOS__)
return _fseek(fp, offset, whence);
#elif SIZEOF_FPOS_T >= 8
/* lacking a 64-bit capable fseek(), use a 64-bit capable fsetpos()
and fgetpos() to implement fseek()*/
fpos_t pos;
switch (whence) {
case SEEK_END:
#ifdef MS_WINDOWS
fflush(fp);
if (_lseeki64(fileno(fp), 0, 2) == -1)
return -1;
#else
if (fseek(fp, 0, SEEK_END) != 0)
return -1;
#endif
/* fall through */
case SEEK_CUR:
if (fgetpos(fp, &pos) != 0)
return -1;
offset += pos;
break;
/* case SEEK_SET: break; */
}
return fsetpos(fp, &offset);
#else
#error "Large file support, but no way to fseek."
#endif
}
os.lseek
函数被定义为 here它几乎是相同的代码,除了它是这样做的:
if (!_PyVerify_fd(fd))
return posix_error();
Py_BEGIN_ALLOW_THREADS
#if defined(MS_WIN64) || defined(MS_WINDOWS)
res = _lseeki64(fd, pos, how);
#else
res = lseek(fd, pos, how);
#endif
Py_END_ALLOW_THREADS
注意对 _PyVerify_fd
的调用!
您可以使用任何 整数对象调用os.lseek
,因此解释器必须验证:
当使用文件对象时,您可以假设与文件对象关联的文件描述符是有效的并避免检查。
因此在这种情况下,低级函数实际上必须执行更多的错误检查,从而使操作变慢。
还有第三种查找文件的方法,即使用io
库。结果是:
$ dd if=/dev/urandom of=test.bin bs=1024 count=1024
1024+0 record dentro
1024+0 record fuori
1048576 byte (1,0 MB) copiati, 0,0851599 s, 12,3 MB/s
$ python2 -m timeit -s 'import io;import os; f=open("test.bin", "r")' 'for i in xrange(10000): f.seek(i, os.SEEK_SET)'
100 loops, best of 3: 5.72 msec per loop
$ python2 -m timeit -s 'import io;import os; f=os.open("test.bin", os.O_RDONLY)' 'for i in xrange(10000): os.lseek(f, i, os.SEEK_SET)'
100 loops, best of 3: 6.28 msec per loop
$ python2 -m timeit -s 'import io;import os; f=io.open("test.bin", "r")' 'for i in xrange(10000): f.seek(i, os.SEEK_SET)'
10 loops, best of 3: 63.8 msec per loop
它们花费的时间是普通文件的 10 倍!但是,如果您查看它们的实现方式 here您会看到它们的实现使用了相当高级的 API,并且与纯 C 版本相比引入了相当多的开销。
另请注意,在我的机器上,os.lseek
和 seek
之间没有 2 倍的差异。
关于python - 为什么 os.lseek() 在类文件对象上比 seek() 慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35528471/
我在看 source code的 cat来自 GNU coreutils,特别是圆检测。他们正在比较设备和 inode 并且工作正常,但是有一个 额外的案例 如果输入为空,它们允许输出为输入。查看代码
我正在尝试将一些文本附加到已打开的文件中。我想在文件末尾附加 pid 号。例如:Lorem ipsum dolor sit amet orci aliquam. 14872 。我的代码工作正常,只是我
我所做的:以相反的顺序复制文件的内容。我不能做什么:向前复制内容。 我在网上进行了研究,发现 lseek() 有这个参数.. lseek(file_descriptor,offset,whence);
通常lseek不适用于 stdin . 但是,如果我像这样运行我的程序会怎样: ./a.out < filename 现在stdin是文件而不是键盘。 威尔lseek在那里工作? 我可以吗 lseek
我有以下 C 代码 long from = atol(buffer); printf("From: %ld\n", from); int file_fd = open(fullPath, O_RDON
我想在文件中写入一些伪造文本(名为helloworld 的文件中的“helloworld”文本),但不是从头开始。我在考虑 lseek() 函数。 如果我使用以下代码(已编辑): #include
我正在尝试使用 lseek 检查我的 txt 文件的大小。不幸的是我不工作。我的 T.Txt 包含 16 个字符:ABCDABCDDABCDABCD 仅此而已。所以数字变量应该有 16+1。为什么是1
考虑以下代码: lseek(fd, 100, 0); /* Seek to the 100th byte in the file fd. */ write(fd, buf, n); /* Write
据我所知,我一直在阅读高级 unix 编程书籍。对文件使用 lseek 并创建一个洞应该使用更少的磁盘空间,因为该洞没有记录在磁盘上并且该洞用零填充。 但是我创建了两个文件,一个有孔,一个没有,但是没
我对 lseek() 的返回值(这是新的文件偏移量)感到困惑 我有文本文件(它的名字是 prwtest)。它的内容被写入 a 到 z。 然后,我写的代码如下, 1 #include 2 #i
我有一个名为“input.txt” 的文件,其中包含一些值。我正在编写程序,它将在该文件中找到最小值,并将该最小值替换为作为命令行参数给出的数字 - 如果该命令行参数大于最小值。这些值代表室温,因此可
我有一个 exec 文件,我知道其中有一个(或多个)字符串“coolyo”的出现,并且需要复制此文件并将所有出现的“coolyo”替换为我的程序收到的参数“使用系统调用。我有一个条目和用汇编语言编写的
char x[3]; char buff, c; x[0]='y'; int offset, i; int fd; fd = open("test1.txt", O_RDONLY); if(fd==-
我正在尝试创建一个简单的程序,它创建一个文件,在其上写入,然后向后移动指针,最后读取它。 #include #include #include #include #include #inclu
必须在下面的程序中使用 lseek 函数...程序只是复制文件(已经存在)。我想复制现有文件以及文件末尾的字符例如:Sorce_File.txt 复制后包含:“1 2 3” Target_File.t
我有一个包含 n 个字节的缓冲区,但我只想从字节 3 读取 sizeof(something) 个字节,这意味着我不想从缓冲区读取字节 1 和 2。例如…… 对于某些缓冲区,字节 1 = 'a',字节
这个问题在这里已经有了答案: Print last 10 lines of file or stdin with read write and lseek [closed] (1 个回答) 关闭 5
我正在用 C 编写一个学术项目,我只能使用 和 库到文件操作。 我有逐行读取文件的功能。算法是: 在文件的开头设置指针并获取当前位置。 以恒定大小将数据读取到缓冲区 ( char buf[100] )
是否可以在不知道每条记录的大小的情况下访问文本文件中的特定记录(使用特定索引)? 最佳答案 如果您维护一个单独的记录偏移量索引,那么您可以简单地查询它以找到要查找的适当位置。否则,不。 关于c++ -
我在使用 lseek 和缓冲区进行分配时遇到了一些问题。目标是读取文件并将每个字母“a”更改为“?”。我正在运行一些小程序来了解函数和缓冲区的工作原理,但我遇到了一些麻烦……想象一下,我的文件“tes
我是一名优秀的程序员,十分优秀!