我正在開發一個綁定到數據網格的BindingList
的WPF GUI(.net 3.5)。我處理BindingList
的ListChangedEvent
,並且我在同一個BindingList
上執行昂貴的linq查詢並更新linq結果中的某些屬性(,它在更新時正確地在GUI上提升和調度INotifyPropertyChanged.PropertyChanged
事件)。運行後臺線程(百萬次)
我的綁定列表可能已經有數百萬條記錄,GUI有時可能會在幾秒鐘內在這些記錄上執行數百萬次事務(添加或刪除)。所以每次交易都會引發ListChangedEvent
事件。
這是我的GUI正在影響,所以我移動LINQ檢查後臺線程。但這裏是這筆交易......
- 爲了得到一致的結果,我必須在產卵一個新的後臺線程每個
ListChangedEvent
接收。這將導致數百萬個線程在幾秒鐘內在內存中產生......內存中的一個非常大的瓶頸。 - 我可能會使用單個後臺工作器,但它不能運行新的異步工作直到完成,因此我們將不得不在GUI線程上等待。 GUI會掛起,這又是一個問題!
我可以檢查bgWorker.IsBusy(),但這將跳過很多
ListChangedEvent
處理,同時工作人員繁忙,從而失去了linq查詢的完整性。想我找到出路,以解決點號2和3以上討論過這個問題,我反正靠每個ASYC工作我做的百萬記錄收集的快照。這將導致大量的越來越創建的本地萬人次的紀錄集合和GCed,也許在幾秒鐘的事......
所以我很困惑什麼解決方案將服務器我最好的...
現有的僞代碼:
....
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同步(我在另一個線程上進行的)只在該進程結束時出現問題。
@CilnE thx的評論...但不會線程隊列線程?它可以排列數百萬?會有什麼影響?我想那時我在每個改變的事件上創建新的後臺工作者,apporach也可以作爲後臺工作者本身在內部使用threapool! – 2012-03-05 06:33:07
ThreadPool專爲排隊大量需要在有限數量的線程上運行的任務而設計。 – zabulus 2012-03-05 06:38:58
@zabulus,Jon Skeet寫了這篇文章http://www.yoda.arachsys.com/csharp/multithreading.html關於後臺工作者如何在內部使用線程池以及由於排隊和由於排隊等原因可能需要很長時間完成任務...所以我的GUI更新在預計的持續時間內保證? – 2012-03-05 06:40:57