我需要在 Django 中为 Web 请求提供服务时启动 pdftk 进程,并等待它完成。我当前的 pdftk 代码如下所示:
proc = subprocess.Popen(["/usr/bin/pdftk",
"/tmp/infile1.pdf",
"/tmp/infile2.pdf",
"cat", "output", "/tmp/outfile.pdf"])
proc.communicate()
只要我在开发服务器下执行(作为用户 www-data
运行),这就可以正常工作。但是,一旦我切换到 mod_wsgi,不做任何更改,代码就会卡在 proc.communicate()
处,并且“outfile.pdf”将保留为零长度的打开文件句柄。
我已经尝试了子进程调用的几种变体(以及普通的旧 os.system)——将 stdin/stdout/stderr 设置为 PIPE 或各种文件句柄没有任何改变。使用“shell=True”可防止 proc.communicate()
挂起,但 pdftk 无法在 devserver 或 mod_wsgi 下创建输出文件。 This discussion似乎表明操作系统信号和 pdftk 可能存在一些我不理解的更深层次的巫术。
是否有任何解决方法可以使这样的子进程调用在 wsgi 下正常工作?我避免使用 PyPDF 来合并 pdf 文件,因为我必须合并足够多的文件(数百个)以至于内存不足(PyPDF 需要在合并它们时保持每个源 pdf 文件在内存中打开)。
我在最近的 Ubuntu、pythons 2.6 和 2.7 下执行此操作。
最佳答案
尝试使用输入和输出文件的绝对文件系统路径。 Apache 下的当前工作目录与运行服务器的目录不同,可以是任何目录。
消除明显的问题后的第二次尝试。
pdftk 程序是一个 Java 程序,它依赖于能够生成/接收 SIGPWR 信号来触发垃圾收集或执行其他操作。问题是在守护进程模式下的 Apache/mod_wsgi 下,信号在请求处理程序线程中被阻塞,以确保它们仅由寻找进程关闭触发事件的主线程接收。当您 fork 进程以运行 pdftk 时,不幸的是它从请求处理程序线程继承了阻塞的 sigmask。这样做的后果是它阻碍了 Java 垃圾收集过程的运行,并导致 pdftk 以奇怪的方式失败。
唯一的解决方案是使用 Celery 并让前端向 Celery 队列提交作业,以便 celeryd 然后 fork 并执行 pdftk。因为这是通过不同于 Apache 创建的进程完成的,所以您不会遇到这个问题。
有关 mod_wsgi 和 pdftk 的更多详细信息,特别是在 Google 网上论坛中。
http://groups.google.com/group/modwsgi/search?group=modwsgi&q=pdftk&qt_g=Search+this+group
关于python - 如何在 wsgi 中启动 pdftk 子进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7543452/