Здравствуйте, alex1010, Вы писали:
A>Есть, скажем, видеопанель, на которую выведены изображения от 5 ip-камер. Интерфейс построен на wpf. A>При создании экземпляров камер/подключении к ним, возможны задержки до 15-20 секунд. A>В результате, если тупо все делать в одно потоке, вся панель подвисает на это время, пока не пройдет инициализация камеры. A>Логичное решение — вынести создание каждой камеры в отдельный поток.
A>Вопрос — на каком уровне это можно сделать? Я могу часть элементов визуальных, относящихся к wpf, вынести в отдельный поток? A>Или все что касается визуального интерфейса wpf нельзя запихивать в созданный вручную, отдельный thread? A>Просто код, где идет инициализация камеры, наворочен и не хочется туда лезть его переделывать.
Выполняйте максимум действий, не связанных с UI, в своих потоках, а при необходимости работы с UI вызывайте Dispatcher.Invoke / Dispatcher.BeginInvoke.
A>я запустил обращение к камере в своей видеопанели таким образом (из UI потока) A>await Task.Run( cam1 ).ConfigureAwait( false ); A>и она подвисла на пару десятков секунд. Т.к внутри cam1 идет доступ к отрисовке UI и пока не закончится, не отвисает. ConfigureAwait не помогает.
Ну обычно данные сначала подготавливаются, а потом выводятся
и солнце б утром не вставало, когда бы не было меня
Есть, скажем, видеопанель, на которую выведены изображения от 5 ip-камер. Интерфейс построен на wpf.
При создании экземпляров камер/подключении к ним, возможны задержки до 15-20 секунд.
В результате, если тупо все делать в одно потоке, вся панель подвисает на это время, пока не пройдет инициализация камеры.
Логичное решение — вынести создание каждой камеры в отдельный поток.
Вопрос — на каком уровне это можно сделать? Я могу часть элементов визуальных, относящихся к wpf, вынести в отдельный поток?
Или все что касается визуального интерфейса wpf нельзя запихивать в созданный вручную, отдельный thread?
Просто код, где идет инициализация камеры, наворочен и не хочется туда лезть его переделывать.
Здравствуйте, alex1010, Вы писали:
A>Вопрос — на каком уровне это можно сделать? Я могу часть элементов визуальных, относящихся к wpf, вынести в отдельный поток?
Если от камер есть эвенты, то можно. Создаете интерфейс — главный поток, в нем инициализируете потоки камер, ловите из них события. НО надо через диспетчер перекидывать выполнение эвентов в главный поток.
Здравствуйте, b0r3d0m, Вы писали:
A>>Или все что касается визуального интерфейса wpf нельзя запихивать в созданный вручную, отдельный thread? B>Нельзя.
Тут все дело в том, что получение видео с камеры делает наш модуль и у нас уже есть видео-панель, без исходников, которая хоть и кривоватая, но не подвисает, пока камера тормозит, пытаясь через synhronizationContext вывести что-то на экран.
Как видеопанель это делает? хз.
интересно, но как это поможет решить проблему, не понял (
Bar().Wait();
await Task.Delay(1000); // здесь как бы вывод на экран
такого в нашем коде и нет — нет Wait, о котором статья.
Просто использование await не работает, т.к в этом await идет отрисовка через synhronizationContext UI. И когда там подвисает, то подвисает и все приложение.
При этом имеющаяся видеопанель как-то ухитряется не виснуть, хотя код модуля с await тот же самый.
я запустил обращение к камере в своей видеопанели таким образом (из UI потока)
await Task.Run( cam1 ).ConfigureAwait( false );
и она подвисла на пару десятков секунд. Т.к внутри cam1 идет доступ к отрисовке UI и пока не закончится, не отвисает. ConfigureAwait не помогает.
Такое впечатление, что имеющийся другой видеоплеер как-то ловит SynchronizationContext.Send и вручную что ли распределяет..
Здравствуйте, alex1010, Вы писали:
A>Есть, скажем, видеопанель, на которую выведены изображения от 5 ip-камер. Интерфейс построен на wpf. A>При создании экземпляров камер/подключении к ним, возможны задержки до 15-20 секунд. A>В результате, если тупо все делать в одно потоке, вся панель подвисает на это время, пока не пройдет инициализация камеры. A>Логичное решение — вынести создание каждой камеры в отдельный поток.
A>Вопрос — на каком уровне это можно сделать?
На любом Делается так же как ина самом первом WPF:
using System;
using System.Windows;
namespace WpfAsyncSample
{
using System.Threading;
using System.Windows.Threading;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Async(Action: () =>
{
// Долго инициализируемся и падаем
Thread.Sleep(2000);
this.RunSyncronously(() => label.Content = "Stage 1 done");
Thread.Sleep(3000);
this.RunSyncronously(() => label.Content = "Stage 2 done");
Thread.Sleep(4000);
throw new Exception("Stage 3 failed");
},
Then: optionalException =>
{
// Мы в UI потокеif (optionalException == null)
{
// Всё ok.
}
else
{
// Инициализация упала.
}
});
}
}
public static class DispatcableExtentions
{
public static void Async(this DispatcherObject ui, Action Action = null, Action<Exception> Then = null)
{
if (Action == null)
throw new ArgumentNullException("AsyncAction");
ThreadPool.QueueUserWorkItem(state =>
{
Exception ex;
try
{
Action();
ex = null;
}
catch (Exception ex2)
{
ex = ex2;
}
if (Then != null)
ui.Dispatcher.BeginInvoke(new Action(() => { Then(ex); }));
});
}
public static void RunSyncronously(this DispatcherObject ui, Action SyncAction)
{
ui.Dispatcher.BeginInvoke(new Action(SyncAction));
}
}
}
Надеюсь ненадо отдельно указывать про то что вместо this.Run() можно писать любой_UI_элемент.Run()
Если надо результаты успешной инициализации передать в UI поток, пользуйтесь замыканиями. Надо показать как?
A>Я могу часть элементов визуальных, относящихся к wpf, вынести в отдельный поток?