Использование Task Parallel Library (C # .NET 4.0) с внешним exe (ffmpeg) без конфликтов - PullRequest
3 голосов
/ 20 декабря 2010

Я пытался решить проблему в течение нескольких дней. Я новичок в многопоточности. Моя цель - запустить несколько задач кодирования видео одновременно с помощью ffmpeg.exe и использовать все возможности сервера.

У меня есть оболочка C #, которая запускает процесс ffmpeg.exe и работает без многопоточности (или только с внутренней потоковой обработкой ffmpeg (недоступно для кодирования flv)), которая выглядит следующим образом:

using (Process process = new Process())
{
    process.StartInfo.FileName = encoderPath + "ffmpeg.exe";

    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.CreateNoWindow = false;

    string arguments = "-y -i " + filenameInput + " -f " + 
        GetVideoFormatName(format) + " -vcodec " + GetVideoCodecName(codec);

    // (most argument setup has been omitted for brevity)
    arguments += " " + filenameOutput + " ";

    process.StartInfo.Arguments = arguments;
    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    process.Start();

    bool succes = LireSortie(process);
    process.WaitForExit();
    process.Close();
    return succes;
}

Код ниже вызывает оболочку. Вторым параметром каждого метода Encode является количество потоков, которое нужно использовать для внутренней многопоточности. Когда я отключаю его, он не работает.

var fm = new FFMpegWrapper();

fm.FilenameInput = "test.mp4";
//VideoInfo videoinfo = fm.GetVideoInfo();
Task[] tasks = {
    Task.Factory.StartNew(
        new Action(()=>{ fm.Encodeto200p("test200p.mp4", 4); })),
    Task.Factory.StartNew(
        new Action(()=>{ fm.EncodetoFlash200p("test200p.flv"); })),
    // ... (calls to other Encode methods ommitted) ...
    Task.Factory.StartNew(
        new Action(()=>{ fm.Encodeto404p("test404p.mp4", 4); })),
    Task.Factory.StartNew(
        new Action(()=>{ fm.EncodetoFlash404p("test404p.flv"); })),
    Task.Factory.StartNew(
        new Action(()=>{ fm.Encodeto720p("test720p.mp4", 4); }))
};

Task.WaitAll(tasks, 5000);

Вы, наверное, задаетесь вопросом, почему я поставил таймаут 5000 для WaitAll(). Это потому, что вызывающий поток ждет неопределенно долго, потому что TPL не обнаруживает конец задач. ffmpeg.exe обрабатывает «останов» в середине кодировки и продолжает работать с 0% ЦП.

Я думаю, что TPL и Process противоречат друг другу. Когда я получаю статус каждой задачи с помощью TPL, она остается «Выполнена» все время. Я хотел бы фиксировать реальные события процессов ffmpeg с помощью TPL (или другого механизма), потому что я хочу предотвратить сбой приложения и хочу управлять успехами и сбоями.

1 Ответ

0 голосов
/ 08 июня 2012

Я сомневаюсь, что проблема в TPL или в каком-либо самодельном механизме, используемом для определения того, заканчивается ли процесс. Я подозреваю, что настоящая причина в том, что ожидание не является неопределенным, а является классическим случаем сбоя из-за давления на конкретный ресурс.

Учитывая ваше описание того, что происходит, и то, что процессор, кажется, находится на низком уровне, ваше давление, вероятно, связано с вводом-выводом или памятью. Я предлагаю профилировать ваше приложение, используя как минимум счетчики производительности (и использовать диспетчер задач для быстрого просмотра на уровне поверхности), чтобы выяснить, что происходит.

Как предположил комментатор, имеет смысл исключить задачу и определить, работают ли один, два или более последовательных вызова для кодирования по крайней мере. Может случиться так, что один конкретный вызов задерживает все (например, ошибка кодирования), а не проблема ресурса.

...