Я разрабатываю графический интерфейс WPF (.net 3.5) с привязкой BindingList
к сетке данных.Я обрабатываю ListChangedEvent
из BindingList
, и в этом я выполняю дорогой запрос linq для того же BindingList
и обновляю определенные свойства в результате linq (, который корректно вызывает и отправляет событие INotifyPropertyChanged.PropertyChanged
в графическом интерфейсепри обновлении ).
Мой список привязок может уже содержать миллионы записей, и GUI иногда может выполнять миллионы транзакций (добавлять или удалять) с этими записями в течение нескольких секунд.Таким образом, каждая транзакция будет вызывать событие ListChangedEvent
.
Именно на это влиял мой графический интерфейс, поэтому я перенес проверку linq на фоновый поток.Но вот сделка ...
- Чтобы получить последовательные результаты, я должен создать новый фоновый поток на каждый
ListChangedEvent
полученный.Это приведет к тому, что миллионы потоков будут порождаться в памяти за несколько секунд ... очень большое узкое место в памяти. - Я могу использовать один фоновый рабочий, но он не может запустить новую асинхронную работу, пока она не будет завершена, поэтомунам придется ждать в потоке GUI.GUI зависнет, и это снова проблема!
Я могу проверить bgWorker.IsBusy (), но это будет пропустить много ListChangedEvent
обработано, пока работник занят, таким образом теряя целостностьзапроса linq.
Предположим, я нашел выход для решения этой проблемы, рассмотренной в пунктах 2 и 3 выше, в любом случае я должен положиться на снимок сбор миллионов записей на каждую работу, которую я выполняю.Это приведет к тому, что большое количество локальных миллионов коллекций записей будет создано и скопировано, возможно, в течение нескольких секунд ...
Так что я запутался, какое решение подойдет мне лучше всего ...
Существующий псевдокод:
....
var bindingList = GetMillionsOfRecordsBindingList();
bindingList.ListChanged += OnEachItemChanged;
mydataGrid.ItemsSource = bindingList;
....
private void OnEachItemChanged(object sender, ListChangedEventArgs e)
{
var currentStauses = GetCurrentStatuses();
var matchedItems = from p in bindingList
where p.RefID != null
and curStauses.Any(status => status.Type == p.Status.Type)
select p;
// We have checked that in production the matchedItems collection
// less than hundred items updated with their statuses at a time.
foreach(var p in matchedItems)
{
p.ShowHighlightAnimation = true; //GUI runs animations on the updated items.
}
}
Мой предложенный псевдокод:
private void OnEachItemChanged(object sender, ListChangedEventArgs e)
{
var bgWrkr = new BackgroundWorker();
// This will spawn millions of threads
// (even if they wait in threadpool we have million threads to finish)
bgWrker.DoWork
+= (o, args) =>
{
var listOfItems = args.Argument as List<MyItems>;
var currentStauses = GetCurrentStatuses();
var matchedItems = from p in bindingList
where p.RefID != null
&& curStauses.Any(status => status.Type == p.Status.Type)
select p;
foreach(var p in matchedItems)
{
p.ShowHighlightAnimation = true;
//GUI runs animations on the updated items.
}
};
bgWrkr.RunWorkerAsync(bindingList.ToList());
}
Я знаю, этот кододинаково плохо .... Следовательно, я запутался в правильном подходе!
Примечание: Я не могу контролировать другой процесс, который выполняет эти миллионы транзакций в списке привязок.Это может быть сделано за несколько секунд или неторопливо за день.Таким образом, синхронизация LINQ (которую я выполняю в другом потоке) только в конце этого процесса исключена.