Partitioner
zwraca elementy w kolejności w jakiej występują one w źródle enumeracji, niezależnie na ile wątków dane będą dzielone. Inaczej mówiąc enumeratory sub-podziałów zwracają elementy w kolejności jak w źródłowej kolekcji niezależnie od tego jak te elementy z sub-podziałów wyciągamy. Narzut synchronizacji dla takiej metody jest dosyć duży. Nie jest ona także przyjazna dla pamięci cache. Zastosowanie takiej metody podziału to np. pobieranie plików z sieci:
- przetwarzanie pojedynczego elementu jest długotrwałe
- wątek przez większość czasu jest zablokowany
- chcemy by elementy były pobierane w porządku występowania w kolekcji
GetDynamicPartitions()
może być wywołany więcej niż jeden raz w trakcie życia SequentialPartitioner
. Stąd w tej metodzie za każdym razem musimy tworzyć nasz nowy współdzielony enumerator. Umieszczenie go w obiekcie było by błędem. yield return
nie umieszczamy w bloku lock
gdyż wynik zostanie zwrócony podczas założonej blokady co w praktyce oznacza sekwencyjne przetwarzanie elementów kolekcji. Wywołanie
return GetDynamicPartitions(m_source.GetEnumerator());
jest konieczne. Jeśli enumerator będziemy tworzyć w głównej metodzie to za każdym wywołaniem metody (pobraniem enumeratora dla osobnego wątku) zostanie on utworzony na nowo. public class SequentialPartitioner<T> : Partitioner<T> { private readonly IList<T> m_source; public SequentialPartitioner(IList<T> a_source) { m_source = a_source; } public override bool SupportsDynamicPartitions { get { return true; } } public override IList<IEnumerator<T>> GetPartitions(int a_partition_count) { var dp = GetDynamicPartitions(); return (from i in Enumerable.Range(0, a_partition_count) select dp.GetEnumerator()).ToList(); } public override IEnumerable<T> GetDynamicPartitions() { return GetDynamicPartitions(m_source.GetEnumerator()); } private static IEnumerable<T> GetDynamicPartitions(IEnumerator<T> a_enumerator) { while (true) { T el; lock (a_enumerator) { if (a_enumerator.MoveNext()) el = a_enumerator.Current; else yield break; } yield return el; } } }
Brak komentarzy:
Prześlij komentarz