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