Python子流程.check_调用([";wine";]..)存在同步问题
我有一个python脚本,它使用Python子流程.check_调用([";wine";]..)存在同步问题,python,python-3.x,subprocess,race-condition,wine,Python,Python 3.x,Subprocess,Race Condition,Wine,我有一个python脚本,它使用子进程。检查调用启动Wine(Linux上的Windows Emulator),然后Wine启动Z:\\Program Files(x86)\\PeaZip\\PeaZip.exe 首先,当我在调试模式下测试这个python脚本时,python3-u-mipdb unpack_archive.py,并在wine启动和运行语句周围逐步设置断点,wine成功运行了peazip.exe。也就是说,peazip在Linux上成功地提取了PEA归档文件 但是,当我在调试模式
子进程。检查调用启动Wine(Linux上的Windows Emulator),然后Wine启动Z:\\Program Files(x86)\\PeaZip\\PeaZip.exe
首先,当我在调试模式下测试这个python脚本时,python3-u-mipdb unpack_archive.py
,并在wine启动和运行语句周围逐步设置断点,wine成功运行了peazip.exe
。也就是说,peazip在Linux上成功地提取了PEA归档文件
但是,当我在调试模式下测试这个python脚本时,发现peazip.exe没有成功地提取PEA归档文件。因此,我怀疑wine或python子流程中存在同步问题
现在我的解决方法是,在启动wine后插入time.sleep(1.0)
:
elif 'PEA archive' in ftype:
if splitext(arcname)[1] != '.pea':
tmpfile = os.path.join(tmpdir, basename(arcname))+'.pea'
else:
tmpfile = os.path.join(tmpdir, basename(arcname))
shutil.copy(arcname, tmpfile)
subprocess.check_call(["wine", "/home/acteam/.wine/drive_c/Program Files (x86)/PeaZip/peazip.exe",
"-ext2here", to_wine_path(tmpfile)])
import time
time.sleep(1.0) # if we don't sleep, then peazip.exe won't extract file successfully
os.remove(tmpfile)
copy_without_symlink(tmpdir, outdir)
我查过了,它没有提到任何关于同步的事情。我也查过了。文档明确表示check_call()将等待命令完成
我不想要这种解决方法,因为如果PEA归档文件非常大,那么sleep()的超时值必须更大,并且在运行它之前,我们无法预测足够的超时值
我提到了他的建议。使用subprocess.check_output()而不是check_call()
我用python3unpack_archive.py Kevin.pea
测试了它,它是一个2.0GB的pea存档。提取过程耗时4分16秒。三个子文件成功解包。我的理解是,wine
可执行文件不是实际的仿真器-它只是启动一个名为wineserver
的后台进程,如果它还没有运行,告诉它运行Windows程序,然后立即退出——很可能是在Windows程序开始运行之前
对的一个回答是,将wine
的输出传输到另一个程序将延迟时间,直到Windows程序实际退出。在Python术语中,这相当于使用check\u output()
而不是check\u call()
,尽管我自己没有尝试过这一点。考虑使用建议锁定来阻止进程,直到进程退出:
lockfile=open(tmpfile, 'a')
subprocess.check_call([
"wine", "/home/acteam/.wine/drive_c/Program Files (x86)/PeaZip/peazip.exe",
"-ext2here", to_wine_path(tmpfile)],
preexec_fn=lambda: fcntl.flock(lockfile, fcntl.LOCK_EX),
close_fds=False)
fcntl.flock(lockfile, fcntl.LOCK_EX)
在这里,我们的preexec\u fn
(在fork()
关闭子流程后运行,但在wine
启动之前)获取一个锁,在check\u call()
返回后,我们自己尝试获取该锁——如果它尚未释放,它将被阻止
(请注意,您需要确保wine不会在程序退出之前关闭该文件描述符本身;如果关闭了,一种避免这种情况的方法是在作为stdin、stdout或stderr传递的描述符上创建锁)。好。我尝试使用wineserver--front
。我发现在peazip.exe
完成提取后,wineserver
也将终止。在启动wineserver
之前,我启动wineserver--front
,并等待wineserver
子进程终止。我尝试了您的示例代码,但遇到了以下异常:`Traceback(最近一次调用):文件“unpack\u archive.py”,第258行,在main()文件“unpack\u archive.py”中,第251行,在main中表示f,解包归档文件(arcname,outdir)中的sha1:解包归档文件关闭文件/usr/lib/python3.4/subprocess.py”中的第169行文件“解包归档文件.py”,第556行,检查调用retcode=call(*popenargs,**kwargs)子进程。子进程错误:preexec\fn中发生异常`这还不够详细--我需要实际的异常。您可以考虑用一个实际函数替换lambda,然后在提升之前打印一个堆栈跟踪。结果是第二个fcntl.flock(lockfile,fcntl.LOCK_EX)
不会等到peazip执行完成。它仍然无法解决竞争条件。我不认为在测试期间已经有wineserver
在运行?(否则,它将不得不关闭所有预先开放的FD以避免锁定……公平地说,这很可能发生)。
lockfile=open(tmpfile, 'a')
subprocess.check_call([
"wine", "/home/acteam/.wine/drive_c/Program Files (x86)/PeaZip/peazip.exe",
"-ext2here", to_wine_path(tmpfile)],
preexec_fn=lambda: fcntl.flock(lockfile, fcntl.LOCK_EX),
close_fds=False)
fcntl.flock(lockfile, fcntl.LOCK_EX)