使用多线程提高速度

时间:2018-06-19 11:32:35

标签: c# .net multithreading

我有一个名为PlaylistView的CustomControl。它在播放列表中显示带有名称和缩略图的元素。 DisplayPlaylist方法可确保启动线程,在该线程中,单个元素被一个一个地添加,并且缩略图(第30帧)被读出:

public void DisplayPlaylist(Playlist playlist)
{
    Thread thread = new Thread(() => DisplayElements(playlist));
    thread.Start();
}

private void DisplayElements(Playlist playlist)
{
    for (int i = 0; i < playlist.elements.Count; i++)
        DisplayElement(playlist.elements[i], i);
}

private void DisplayElement(IPlayable element, int index)
{
    VideoSelect videoSelect = null;

    if (element is Audio)
        //
    else if (element is Video)
        videoSelect = new VideoSelect(index, element.name, GetThumbnail(element.path, SystemData.thumbnailFrame));

    videoSelect.Location = GetElementsPosition(index);

    panel_List.BeginInvoke(new Action(() => 
    {
        panel_List.Controls.Add(videoSelect);
    }));
}

private Bitmap GetThumbnail(string path, int frame)
{
    VideoFileReader reader = new VideoFileReader();
    try
    {
        reader.Open(path);

        for (int i = 1; i < frame; i++)
            reader.ReadVideoFrame();

        return reader.ReadVideoFrame();
    }
    catch
    {
        return null;
    }
}

但是有问题。

它太慢了(大约10个元素/秒)。播放列表的长度为614,您将需要等待一分钟以上,直到所有内容都显示出来。每次更改播放列表(例如添加或删除项目)时,该过程都会从新项目开始。加2或更多会使它变得更加复杂。

我现在可以使用多个线程,并且用户可以指定使用的线程数(1到最大10)。当前代码中的实现如下所示(与以前发布的代码相比,只有更改的部分)

public void DisplayPlaylist(Playlist playlist)
{
    for (int i = 0; i < SystemData.usedDisplayingThreads; i++)
    {
        Thread thread = new Thread(() => DisplayElements(playlist, i));
        thread.Start();
    }
}

private void DisplayElements(Playlist playlist, int startIndex)
{
    for (int i = startIndex; i < playlist.elements.Count; i += SystemData.usedDisplayingThreads)
        DisplayElement(playlist.elements[i], i);
}

问题在于,GetThumbnail函数现在经常返回null,因此会发生错误。另外,System.AccessViolationException经常被扔掉。

我认为,这样做的原因是存在多个同时激活的VideoFileReaders。但是,我不知道到底是什么引发了该问题,因此我无法提出任何解决方案。也许您知道实际的触发因素是什么以及如何解决问题,或者您还知道其他提高速度的方法,但也许更优雅。

1 个答案:

答案 0 :(得分:1)

我将从记录GetThumbnail方法中引发的异常开始。您的代码将其隐藏并返回null。更改为catch (Exception exc),在日志中写入异常详细信息,或者至少在调试器中进行评估。这可以给出提示。

我也很确定您的VideoFileReader实例是IDisposable的,因此您必须通过调用reader.Close()来处置它们。也许以前的实例没有被处理,而您试图多次打开同一文件。

更新:视频帧也必须被丢弃。如果阅读器引用了位图并阻止了处置,则可能需要复制位图。