Vyk*_*tor 14 python windows io large-files python-3.x
我用我的python脚本创建大文件(1GB实际上有8个).在我创建它们之后,我必须创建将使用这些文件的进程.
该脚本如下所示:
# This is more complex function, but it basically does this:
def use_file():
subprocess.call(['C:\\use_file', 'C:\\foo.txt']);
f = open( 'C:\\foo.txt', 'wb')
for i in 10000:
f.write( one_MB_chunk)
f.flush()
os.fsync( f.fileno())
f.close()
time.sleep(5) # With this line added it just works fine
t = threading.Thread( target=use_file)
t.start()
Run Code Online (Sandbox Code Playgroud)
但应用程序use_file行为foo.txt是空的.有一些奇怪的事情发生了:
C:\use_file C:\foo.txt在控制台中执行(脚本完成后),我得到正确的结果use_file()在另一个python控制台中手动执行,我得到正确的结果C:\foo.txt在open()被调用后立即在磁盘上可见,但0B在脚本结束之前一直保持大小time.sleep(5)它只是按预期开始工作(或者更确切地说是必需的)我已经发现:
os.fsync()但它似乎没有工作(从结果use_file作为是否C:\foo.txt是空的)buffering=(1<<20)(打开文件时)似乎也不起作用我对这种行为越来越好奇.
问题:
close()操作进入后台吗?这记录在哪里?sleep:是windows/python的bug吗?注意:(对于另一方出现问题的情况)应用程序use_data使用:
handle = CreateFile("foo.txt", GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
size = GetFileSize(handle, NULL)
Run Code Online (Sandbox Code Playgroud)
然后size从中处理字节foo.txt.
Kat*_*iel 10
f.close()调用f.flush(),将数据发送到OS.这并不一定是数据写入磁盘,因为操作系统对其进行缓冲.正如您所做的那样,如果您想强制操作系统将其写入磁盘,您需要os.fsync().
您是否考虑过直接将数据传输到use_file?
编辑:你说os.fsync()"不起作用".澄清,如果你这样做
f = open(...)
# write data to f
f.flush()
os.fsync(f.fileno())
f.close()
import pdb; pdb.set_trace()
Run Code Online (Sandbox Code Playgroud)
然后查看磁盘上的文件,它有数据吗?
编辑:使用特定于Python 3.x的信息进行更新
在https://bugs.python.org/issue4944上有一个超级老错误报告讨论了一个可疑的类似问题.我做了一个小测试,显示了这个错误:https://gist.github.com/estyrke/c2f5d88156dcffadbf38
在上面的bug链接中从用户eryksun获得了精彩的解释之后,我现在明白为什么会发生这种情况,并且它本身并不是一个bug.在Windows上创建子进程时,默认情况下它会从父进程继承所有打开的文件句柄.因此,您所看到的实际上可能是共享冲突,因为您尝试在子进程中读取的文件是打开的,可以通过另一个子进程中的继承句柄进行写入.导致此事件的可能事件序列(使用上面Gist中的复制示例):
Thread 1 opens file 1 for writing
Thread 2 opens file 2 for writing
Thread 2 closes file 2
Thread 2 launches child 2
-> Inherits the file handle from file 1, still open with write access
Thread 1 closes file 1
Thread 1 launches child 1
-> Now it can't open file 1, because the handle is still open in child 2
Child 2 exits
-> Last handle to file 1 closed
Child 1 exits
Run Code Online (Sandbox Code Playgroud)
当我编译简单的C子程序并在我的机器上运行脚本时,它在大多数情况下使用Python 2.7.8在至少一个线程中失败.使用Python 3.2和3.3,没有重定向的测试脚本不会失败,因为close_fds参数的默认值subprocess.call现在True是在不使用重定向时.在这些版本中,使用重定向的其他测试脚本仍然失败.在Python 3.4中,两个测试都成功,因为PEP 446默认情况下使所有文件句柄都不可继承.
从Python中的线程生成子进程意味着子进程继承所有打开的文件句柄,甚至从生成子进程的其他线程继承.至少对我来说,这不是特别直观.
可能的解决方案:
close_fds=True给subprocess.call完全禁用继承(这是Python 3.x中的默认值).请注意,这可以防止重定向子进程的标准输入/输出/错误.os.open打开带有该os.O_NOINHERIT标志的文件.
tempfile.mkstemp 也使用这个标志.请改用win32api.传递lpSecurityAttributes参数的NULL指针也会阻止继承描述符:
from contextlib import contextmanager
import win32file
@contextmanager
def winfile(filename):
try:
h = win32file.CreateFile(filename, win32file.GENERIC_WRITE, 0, None, win32file.CREATE_ALWAYS, 0, 0)
yield h
finally:
win32file.CloseHandle(h)
with winfile(tempfilename) as infile:
win32file.WriteFile(infile, data)
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
5312 次 |
| 最近记录: |