1

我想同时写入大量文件(比如 10000 个文件)。我发现我可以为此使用多处理。我随意选择使用 100 个进程来编写这些文件。我需要知道是否有办法找到要使用的最佳进程数?在此代码或所有进程自动终止之后,我还需要进行任何清理吗?

我还想知道是否有更有效的方法可以同时写入大量文件。

from multiprocessing import Pool

def write(x):
    fopen=open('file_'+str(x),'w')
    fopen.write('anything')
    fopen.close()

if __name__ == '__main__':
    pool = Pool(processes=100)              
    pool.map(write, range(10000))          
4

1 回答 1

1

首先,对于纯 I/O,threading可能和 一样好multiprocessing,而且通常更好。它也没有关于“我需要任何清理”的谜团。所以,你可能想测试一下。

其次,如果您想知道最快的方法来做到这一点,唯一真正的选择是测试、使用timeit,或者您的 shelltime或等效的。听起来你已经在这样做了。如果您正在寻找一种方法来根据您可以阅读的系统信息(SSD 与 10K HD 与 5200 HD 与远程共享​​、LAN 与 WAN、快速 LAN 与慢速 LAN)以编程方式确定理想池大小、SMB 与 NFS、Windows 与 POSIX 等),您可能需要在各种机器上进行测试并进行一些统计分析。而且其中一些信息不是静态可用的,因此您确实需要启动该过程,然后随时调整池大小。这将非常复杂——我猜所有这些工作大多数时候只会让你获得 10% 的收益。

如果您真的需要从文件 I/O 中挤出最后几个百分点,您可能需要降低一两个级别。

至少,您可能希望将 Python 和/或 stdio 缓冲区从等式中删除(假设文件真的这么小)并使用os.openand os.write。创建字节的原始缓冲区而不是字符串甚至可能会有所帮助(特别是如果这是 Python 3)。如果您实际上正在向每个文件甚至只是向许多文件写入完全相同的内容,则使用相同的缓冲区可能会让操作系统识别您正在向多个文件写入相同的内容,这意味着缓存可以是完美的刚刚接近完美。

您甚至可能想要下拉到特定于平台的 API。例如,在 Windows 上,使用重叠 I/O 允许操作系统尽可能高效地调度写入,并且围绕 IOCP 创建一个本地线程池来处理完成也消除了写入调度之上的所有开销。(您可以通过或访问CreateFileWriteFileEx等。或在 google 中搜索“IOCP Python”以获取示例代码——这些都是不完整或部分不相关的,尤其是因为其中大部分是为执行 c10k 套接字服务器而设计的,但它至少会演示在 MSDN 的帮助和反复试验的帮助下,足以自己将其余部分放在一起。)我想不出 POSIX 上的任何等效项(嗯,等效于ctypeswin32apiaio_writeWriteFileEx,但据我所知,它不会帮助任何真实世界的 *nix 平台上的性能)。

或者,您可能想要上移一步。如果您真的要将相同的数据写入所有或只是许多文件,为什么不将其写入一个文件,然后要求操作系统复制该文件?它也许能够做得更好。

或者,更简单——而且速度更快——将其写入一个文件,然后将其余部分创建为硬链接或符号链接。


既然您询问了最后一个选项:

创建链接背后的想法是您只创建一个文件,但创建 10000 个不同的名称来访问它。

这意味着如果您编辑一个文件,则所有 10000 个文件都会被编辑。如果那不是您想要的,则链接不合适。

但如果它是你想要的,有两种基本的链接:硬链接和符号链接。

现代文件系统允许多个目录条目指向同一个文件。创建硬链接是一种创建另一个目录条目的方法,该目录条目指向与现有文件相同的文件。在 Python 中,您可以使用os.link. 所以:

with open('file_0', 'w') as f:
    f.write('anything')
for i in range(1, 10000):
    os.link('file_0', 'file_{}'.format(i))

现在您的文件系统有 10000 个file_0通过命名的条目file_9999,但它们都是磁盘上相同实际数据的名称。编辑一个,其他 9999 全部更改。删掉一个,剩下的9999还在。

硬链接有一些小问题,还有一个主要问题。小问题是每个平台对除了常规文件之外的东西的硬链接有不同的规则,而且你通常不能跨文件系统进行硬链接。主要问题是Windows。首先,您需要类似(在我脑海中)Vista 和 NTFS 6 来获得完全支持,Win2000 和 NTFS 4 来获得部分支持。但是,更重要的是,os.link在 Windows 上不存在。因此,您必须使用ctypesorwin32api调用底层CreateHardLink函数(或subprocess运行mklinkorfsutil命令)。

符号链接是更高层次的想法。它是一种特殊类型的文件,它通过路径引用另一个文件。这意味着您可以读取有关符号链接本身的信息(参见statvs. lstat),创建保存链接信息的 tarball,等等。这也意味着如果您 delete file_0,所有其他链接都将变为指向不存在的文件的断开链接. 无论如何,在 Python 中,您可以使用os.symlink它们来创建它们(使用与上面完全相同的代码)。

符号链接没有硬链接的大部分限制,但对于 Windows 来说更糟——在 Vista 之前根本没有符号链接,普通文件与目录的不同规则,可以遍历的链接数量的限制,需要特殊权限哪些非管理员用户没有,等等。当然你不能os.symlink从 Python 中使用。

还有一些特定于平台的东西,例如 Windows 快捷方式和 Mac 别名,它们与符号链接具有相似但不相同的功能。

于 2013-02-18T20:18:34.657 回答