7

Webサーバーで実行されるPythonスクリプトがあります。main関数が呼び出され、それが返されると、数秒間スリープしてから再度呼び出されます。目的は、ユーザーが追加した新しいアップロードされたビデオをピックアップしてwebmに変換し、中央のフレームを画像やその他のファンキーなものとして引き出すことです。ffmpegへの外部呼び出しを使用しています。以下のコードクリップは、私がそれをどのように呼ぶかを示しています。

    duration = output[durationIndex+10:durationIndex+18]
    durationBits = duration.split(":")
    lengthInSeconds = (int(durationBits[0])*60*60) + (int(durationBits[1])*60) + (int(durationBits[2]))

    child = subprocess.Popen(["ffmpeg","-y","-i",sourceVideo,"-f","mjpeg","-vframes","1","-ss",str(lengthInSeconds/2),destination], shell=True, stderr=subprocess.PIPE)
    output = ""
    while True:
        out = child.stderr.read(1)
        if out == '' and child.poll() != None:
            break
        if out != '':
            output += out

    updateSQL = "update `videos_graduatevideo` set thumbnail = '" + str(destination) + "' where `original_video` = '" + sourceVideo + "'"
    cursor.execute(updateSQL)

このスクリプトはWindowsマシンのATMで実行されていますが、開発が完了したら、おそらくUnixシステムにデプロイします。

問題は。実行を続けるには、このPythonスクリプトが必要です。ffmpegで問題が発生し、スクリプトがハングした場合、ユーザーがアップロードした動画は、Pythonスクリプトを突くまで、「保留中」の状態のままになります。私が持っている特定のmovファイルがffmpegを無期限にハングさせることを知っています。どういうわけか、プロセスが実行されている時間を確認し、実行時間が長すぎる場合はプロセスを強制終了することができますか?

4

5 に答える 5

6

アーキテクチャにMQを検討することでメリットが得られるように思われるという点で、S。Lottに同意しますが、この特定の問題については、Popenを使用しても問題ないと思います。

作成するプロセスごとに、作成時間を節約します(のようなものdatetime.datetime.today()で十分です)。次に、1分ごとに、開いているプロセスと時間のリストを調べ、Popen.send_signal(signal)、terminate()、またはkill()を使用して、そこにあるべきではないプロセスと時間を取得します。

例:

import time
from subprocess import Popen
from datetime import datetime
jobs = []
max_life = 600 # in seconds

def reap_jobs(jobs):
  now = datetime.datetime.today()
  for job in jobs:
    if job[0] < now - datetime.timedelta(seconds=max_life)
      job[1].kill()
      # remove the job from the list if you want. 
      # but remember not to do it while iterating over the list

for video in list_of_videos:
  time = datetime.datetime.today()
  job = Popen(...)
  jobs.append((time,child))

while True:
  reap_jobs(jobs)
  time.sleep(60)
于 2011-12-28T15:49:33.447 に答える
1

制御スクリプトはそれを開始したものであり、システムリソースの使用量ではなく、時間に基づいて強制終了する必要があるため、かなり単純なはずです。以下は、いくつかの変更を加えたサンプルコードです。コメントのある行を探します。

import time
timeout = 60 #child is allowed to run for 1 minute.
duration = output[durationIndex+10:durationIndex+18]
durationBits = duration.split(":")
lengthInSeconds = (int(durationBits[0])*60*60) + (int(durationBits[1])*60) + (int(durationBits[2]))

child = subprocess.Popen(["ffmpeg","-y","-i",sourceVideo,"-f","mjpeg","-vframes","1","-ss",str(lengthInSeconds/2),destination], shell=True, stderr=subprocess.PIPE)
killtime = time.time() + timeout #timestamp after which the child process should be killed
output = ""
while True:
    out = child.stderr.read(1)
    if out == '' and child.poll() != None:
        break
    if out != '':
        output += out
    if time.time() > killtime: #check if 60 seconds have passed
        child.kill() #tell the child to exit
        raise RuntimeError("Child process still going %i seconds after launch" %killtime) #raise an exception so that updateSQL doesn't get executed

updateSQL = "update `videos_graduatevideo` set thumbnail = '" + str(destination) + "' where `original_video` = '" + sourceVideo + "'"
cursor.execute(updateSQL)

他に何をする必要があるかに応じて、RuntimeErrorを別のものに変更したり、例外を発生させる代わりにフラグを設定したりすることができます。child.kill()行を指定すると、子プロセスが停止しますが、これを終了するための最も適切な方法ではない場合があります。posixシステムにデプロイする場合は、代わりにos.system('kill -s 15%i'%child.pid)を使用して、より適切に強制終了できます。

于 2012-01-03T11:29:35.713 に答える
0

実行中のすべてのプロセスとシステム使用率(CPU、ディスク、メモリ)に関する情報を移植可能な方法で取得するためのインターフェイスを提供するpythonモジュールがあり、ps、top、df、kill、などのコマンドラインツールによって提供される多くの機能を実装します。 free、lsof、free、netstat、ifconfig、nice、ionice、iostato、iotop、uptime、tty:psutil。それは役立つはずです。

于 2011-12-30T22:06:40.213 に答える
-1

指定したプロセスを監視し、監視条件に応じていくつかのアクションを実行する神-プロセスモニターを見てください。たとえば、CPU使用率を監視し、CPU使用率が50%を超えている場合は、プロセスを再開できます。

# code in Ruby
# copyied from the documentation
w.restart_if do |restart|   
  restart.condition(:cpu_usage) do |c|
    c.above = 50.percent
    c.times = 5
  end
end
于 2011-12-28T16:02:45.580 に答える
-3

手順1.CGIスクリプトを使用しないでください。フレームワークを使用します。

手順2.応答を作成する関数でサブプロセスを直接開始しないでください。セロリを使用します。

このプロセスは、サーバー上で常に実行されています。フレームワークから独立しており、djangoが設定するのと同じデータベースから読み取ります

ステップ2、もう一度。このサブプロセスを常に実行したままにしないでください。Celeryを使用して、リクエストが到着したときに開始され、そのリクエスト(およびそのリクエストのみ)を処理してから停止するようにします。

于 2011-12-22T12:23:42.813 に答える