私は最初の並列アプリケーションを書き始めています。IDataReader
このパーティショナーは、データソースから一度にプルchunkSize
するレコードを列挙します。
TLDR; バージョン
private object _Lock = new object();
public IEnumerator GetEnumerator()
{
var infoSource = myInforSource.GetEnumerator();
//Will this cause a deadlock if two threads
lock (_Lock) //use the enumator at the same time?
{
while (infoSource.MoveNext())
{
yield return infoSource.Current;
}
}
}
完全なコード
protected class DataSourcePartitioner<object[]> : System.Collections.Concurrent.Partitioner<object[]>
{
private readonly System.Data.IDataReader _Input;
private readonly int _ChunkSize;
public DataSourcePartitioner(System.Data.IDataReader input, int chunkSize = 10000)
: base()
{
if (chunkSize < 1)
throw new ArgumentOutOfRangeException("chunkSize");
_Input = input;
_ChunkSize = chunkSize;
}
public override bool SupportsDynamicPartitions { get { return true; } }
public override IList<IEnumerator<object[]>> GetPartitions(int partitionCount)
{
var dynamicPartitions = GetDynamicPartitions();
var partitions =
new IEnumerator<object[]>[partitionCount];
for (int i = 0; i < partitionCount; i++)
{
partitions[i] = dynamicPartitions.GetEnumerator();
}
return partitions;
}
public override IEnumerable<object[]> GetDynamicPartitions()
{
return new ListDynamicPartitions(_Input, _ChunkSize);
}
private class ListDynamicPartitions : IEnumerable<object[]>
{
private System.Data.IDataReader _Input;
int _ChunkSize;
private object _ChunkLock = new object();
public ListDynamicPartitions(System.Data.IDataReader input, int chunkSize)
{
_Input = input;
_ChunkSize = chunkSize;
}
public IEnumerator<object[]> GetEnumerator()
{
while (true)
{
List<object[]> chunk = new List<object[]>(_ChunkSize);
lock(_Input)
{
for (int i = 0; i < _ChunkSize; ++i)
{
if (!_Input.Read())
break;
var values = new object[_Input.FieldCount];
_Input.GetValues(values);
chunk.Add(values);
}
if (chunk.Count == 0)
yield break;
}
var chunkEnumerator = chunk.GetEnumerator();
lock(_ChunkLock) //Will this cause a deadlock?
{
while (chunkEnumerator.MoveNext())
{
yield return chunkEnumerator.Current;
}
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<object[]>)this).GetEnumerator();
}
}
}
IEnumerable
渡されたオブジェクトをスレッドセーフにしたかったのですが( MSDNの例では、PLINQとTPLがそれを必要とする可能性があると想定しています)_ChunkLock
、下部近くのロックはスレッドセーフを提供するのに役立ちますか、それともデッドロックを引き起こしますか?ドキュメントから、ロックが解放されるかどうかはわかりませんでしたyeld return
。
また、私がやろうとしていることを実行する.netの機能が組み込まれている場合は、それを使用したいと思います。また、コードに他の問題が見つかった場合は、よろしくお願いします。