피드백 열거 자로 구현 된 끝없는 열거 형을 반복하는 간단한 프로그램이 있습니다. 나는 TPL과 PLINQ에서 이것을 구현했다. 두 예 모두 예측 가능한 반복 횟수 (PLINQ의 경우 8 개, TPL의 경우 3 개)를 초과하면 멈 춥니 다. TPL/PLINQ를 사용하지 않고 코드가 실행되면 정상적으로 실행됩니다. 난 threadsafe 방식뿐만 아니라 비 threadsafe 방식으로 열거자를 구현했다. 전자의 경우 병렬 처리 수준이 1로 제한되는 경우 사용할 수 있습니다 (예제의 경우와 동일). non-threadsafe 열거 자 (unsumerafe enumerator)는 매우 간단하며 '멋진'.NET 라이브러리 클래스에 의존하지 않습니다. 병렬 처리 수준을 높이면 교착 상태가 증가하기 전에 수행되는 반복 횟수가 늘어납니다. 예를 들어 PLINQ의 경우 반복 횟수는 8 * 병렬 처리 수준입니다.
열거 (비 스레드)
반복 열거 자의 PLINQ 반복으로 인해 교착 상태가 발생합니다.
public class SimpleEnumerable<T>: IEnumerable<T>
{
private T _value;
private readonly AutoResetEvent _releaseValueEvent = new AutoResetEvent(false);
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
while(true)
{
_releaseValueEvent.WaitOne();
yield return _value;
}
}
public void OnNext(T value)
{
_value = value;
_releaseValueEvent.Set();
}
}
열거 (스레드)
public class SimpleEnumerable<T>: IEnumerable<T>
{
private readonly BlockingCollection<T> _blockingCollection = new BlockingCollection<T>();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
while(true)
{
yield return _blockingCollection.Take();
}
}
public void OnNext(T value)
{
_blockingCollection.Add(value);
}
}
PLINQ 예 : 여기
는 반복자이다,745,
public static void Main(string[] args)
{
var enumerable = new SimpleEnumerable<int>();
enumerable.OnNext(0);
enumerable
.Do(i => Debug.WriteLine($"{i} {Thread.CurrentThread.ManagedThreadId}"))
.AsParallel()
.WithDegreeOfParallelism(1)
.ForEach
(
i =>
{
Debug.WriteLine($"{i} {Thread.CurrentThread.ManagedThreadId}");
enumerable.OnNext(i+1);
}
);
}
TPL 예 : 호출 스택의 내 분석에
public static void Main(string[] args)
{
var enumerable = new SimpleEnumerable<int>();
enumerable.OnNext(0);
Parallel.ForEach
(
enumerable,
new ParallelOptions { MaxDegreeOfParallelism = 1},
i =>
{
Debug.WriteLine($"{i} {Thread.CurrentThread.ManagedThreadId}");
enumerable.OnNext(i+1);
}
);
}
자료, PLINQ 및 TPL에서 모두 파티션 프로그램과 관련된 방법에서 발생하는 교착 상태가 나타납니다,하지만 난 아니다 이것을 어떻게 해석해야하는지.
시행 착오를 거쳐 PLINQ enumerable
을 Partitioner.Create(enumerable, EnumerablePartitionerOptions.NoBuffering)
에 수정했지만 교착 상태가 발생하는 이유를 모르겠습니다.
나는 버그의 근본 원인을 찾는 것에 매우 관심이 있습니다.
인위적인 예제입니다. 나는 코드의 비평을 찾고있는 것이 아니라 이 교착 상태가되는 이유를 찾고있다. 특히, PLINQ 예제에서 .AsParallel()
및 .WithDegreeOfParallelism(1)
행이 주석 처리 된 경우 코드는 올바르게 작동합니다.
PLINQ와 Parallel은 교착 상태를 일으키지 않습니다. 현재 스레드를 N 명의 다른 사람들과 함께 사용하여 병렬로 데이터를 처리합니다. –
@PanagiotisKanavos 분명히 교착 상태가 반복기에 있습니다. 언뜻보기에, 나는 놀랍지는 않습니다. 확실히 안전하지 않습니다. – Servy
@Servy 가장 분명한 문제로 시작했습니다. 이터레이터는 아주 이상한 구조입니다. 간단한 10K int 배열은 병렬 실행을 테스트하기에 충분합니다. Interlocked.Increment는 카운트를 유지하는 아주 좋은 방법입니다. 이 반복자는 그냥 블록 –