上午,
我正在编写一个需要将视频转换为.mp4格式的python守护程序。 为了做到这一点,我计划通过子流程使用Handbrake,但我得到了混合的结果:有时候它会起作用,有时这个过程甚至不会出现在最佳状态。
我不确定发生了什么。我尝试了一些变体,例如使用Shell = True,但问题仍然存在。
谢谢,
#! /usr/bin/python
# -*- coding: utf-8 -*-
import os, time, threading, psutil, resource, logging, subprocess as sp, sys
from Queue import Queue
from threading import Thread
SERVER_LOG=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'convertCentral.log')
logging.basicConfig(format='[%(asctime)s.%(msecs).03d] %(message)s', datefmt='%Y-%m-%d %H:%M:%S', filename=SERVER_LOG, level=logging.INFO)
class QueueServer(object):
current_video_queue = Queue(maxsize=0)
N_WORKER_THREADS = 1
counter = 0
def __init__(self):
print("[QueueServer] Initializing the video conversion queue")
t = threading.Thread(target=self.monitor)
t.start()
''' Alters the process' niceness in order to throtle the CPU usage '''
def preexec_fn(self):
pid = os.getpid()
ps = psutil.Process(pid)
ps.set_nice(10)
resource.setrlimit(resource.RLIMIT_CPU, (1, 1))
''' Converts the video using Handbrake via subprocess'''
def convertVideo(self, video):
print("Now converting %s" % video)
fileName, fileExtension = os.path.splitext(video)
payload = "ulimit -t 360; nice -n 15 HandBrakeCLI -i %s -e x264 -q 15 -o %s.mp4" % (video, fileName)
payload = payload.split(" ")
# Fire in the hole
pr = sp.Popen(payload, stdout=open('/dev/null', 'w'), stderr=sp.STDOUT)
print("Fired.")
pr.wait()
self.counter = self.counter + 1
print("Conversion's done. %d" % self.counter)
''' A worker thread '''
def worker(self):
while True:
print("Getting one")
item = self.current_video_queue.get()
print("Firing conversion: %s" % item)
self.convertVideo(item)
self.current_video_queue.task_done()
print("All done")
def monitor(self):
for i in range(self.N_WORKER_THREADS):
print("Firing thread")
t = Thread(target=self.worker)
t.daemon = True
t.start()
''' Adds a video to the video conversion queue '''
def add(self, video):
print("* Adding %s to the queue" % video)
self.current_video_queue.put(video)
print("* Added %s to the queue" % video)
q = QueueServer()
q.add('UNKNOWN_PARAMETER_VALUE.WMV')
#time.sleep(500)
以下是我在日志上的内容:
Hal@ubuntu:~/Desktop/$ python threadedqueue.py
[QueueServer] Initializing the video conversion queue
Firing thread
* Adding UNKNOWN_PARAMETER_VALUE.WMV to the queue
* Added UNKNOWN_PARAMETER_VALUE.WMV to the queue
Getting one
Firing conversion: UNKNOWN_PARAMETER_VALUE.WMV
Now converting UNKNOWN_PARAMETER_VALUE.WMV
所以,我们可以告诉子进程实际运行,但它只是神秘地死在那里...... 可能导致这种情况的任何想法?
答案 0 :(得分:2)
首先,你提供的有效载荷可能不是你想要的。
在正常操作中,子进程不会将命令提供给shell,而是启动名为args [0]的进程,并将所有其他参数直接传递给它。你正在做的是通过以下论点:
["-t", "360;", "nice", "-n", "15", "HandBrakeCLI", "-i", "someInput", "-e", "x264", "-q", "15", "-o", "someOutput.mp4"]
...到非常混淆的ulimit进程。 相反,你想要的是使用shell = True,并提供args作为字符串。这告诉Popen,而不是实际启动你请求的进程,而不是启动一个shell并将它作为一个单行转储。
payload = "ulimit -t 360; nice -n 15 HandBrakeCLI -i %s -e x264 -q 15 -o %s.mp4" % (video, fileName)
pr = sp.Popen(payload, shell=True, stdout=sp.DEVNULL, stderr=sp.STDOUT)
print('Started handbrake')
pr.wait()
如果你没有打印出“已开始的手刹”,那么期待Popen出现严重错误。调试它的一个好方法是获取有效负载,导入子进程并尝试在交互式控制台上使用Popen打开它。如果您被锁定在Popen呼叫中,则ctrl-c应该会让您跟踪您正在悬挂的内部,这可能反过来为您提供一些帮助。即使它对你没有意义,也可能有助于其他人告诉你发生了什么。
我希望这有用!
答案 1 :(得分:1)
你可以在Python中模仿ulimit -t
,nice -n
,在没有shell的情况下运行HandBrakeCLI
:
#!/usr/bin/env python
import os
import resource
import shlex
from subprocess import call, STDOUT
DEVNULL = open(os.devnull, 'wb', 0)
# quote filenames to allows names with spaces
path, output_path = map(shlex.quote, [video, filename + '.mp4'])
cmd = "HandBrakeCLI -i {path} -e x264 -q 15 -o {output_path}".format(**vars())
def limit_resources():
resource.setrlimit(resource.RLIMIT_CPU, (360, 360)) # emulate ulimit -t
os.nice(15) # emulate nice -n
rc = call(shlex.split(cmd), stdout=DEVNULL, stderr=STDOUT,
preexec_fn=limit_resources)