c# - 使用多线程提高速度
问题描述
我有一个名为 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
返回,所以出现错误。此外,aSystem.AccessViolationException
经常被抛出。
在我看来,原因是存在多个同时处于活动状态的 VideoFileReader。但是,我不知道究竟是什么触发了这个问题,所以我无法提出任何解决方案。也许您知道实际的触发器是什么以及如何解决问题,或者您还知道其他提高速度的方法,这可能更优雅。
解决方案
我将从记录 GetThumbnail 方法中引发的异常开始。您的代码将其隐藏并返回 null。更改为catch (Exception exc)
,在日志中写入异常详细信息或至少在调试器中进行评估。那可以给个提示。
此外,我很确定您的 VideoFileReader 实例是 IDisposable,因此您必须通过调用reader.Close()
. 也许以前的实例没有被处理,你正试图多次打开同一个文件。
更新:视频帧也必须被处理。如果阅读器引用它并防止处置,您可能需要复制位图。
推荐阅读
- timeserieschart - 在 Shiny 中,如何模拟和绘制随时间变化的时间序列
- html - 带有 RStudio 和 xaringan 的垂直可滚动代码
- python - Instabot 不使用烧瓶网络应用程序
- java - 如何通过 OkHttp 和 Retrofit 为 Spring 应用程序提供凭据
- c++ - ShellExecuteA - 可执行文件不会从 %appdata% 运行
- python - X 每个样本有 19257 个特征;期待 19234,同时使用 Logistic 回归 Pickle 模型进行预测
- .net - NullReferenceException:对象引用未设置为对象 .NET Core 的实例
- javascript - 达到某个值时禁用向左滚动
- angular - 如何在 FullCalendar 中仅显示当前月份的事件?
- c# - 在使用 azure auth 之前,使用带有自定义登录屏幕的 BFF 在“/”上提供受身份验证保护的 SPA