RecyclableList.IndexOf parallel performance improvements.
This commit is contained in:
1 parent
99600d4854
commit
3db10d7602
21 files changed
+4282
-511
No files matched your search
@@ -0,0 +1,117 @@
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Recyclable.Collections.Parallel
|
||||
{
|
||||
public sealed class BarrierSlimmer : IDisposable
|
||||
{
|
||||
private static readonly ObjectPool<BarrierSlimmer> _defaultPool = new DefaultObjectPool<BarrierSlimmer>(new DefaultPooledObjectPolicy<BarrierSlimmer>());
|
||||
private ObjectPool<BarrierSlimmer>? _assignedPool;
|
||||
private readonly SpinLock _lock = new(false);
|
||||
|
||||
public bool HasParticipants;
|
||||
public int Participants;
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public void AddParticipant()
|
||||
{
|
||||
bool isLocked = false;
|
||||
_lock.Enter(ref isLocked);
|
||||
|
||||
Participants++;
|
||||
if (Participants == 1)
|
||||
{
|
||||
HasParticipants = true;
|
||||
}
|
||||
|
||||
if (isLocked)
|
||||
{
|
||||
_lock.Exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public void RemoveParticipant()
|
||||
{
|
||||
if (!HasParticipants)
|
||||
{
|
||||
ThrowNoMoreParticipants();
|
||||
}
|
||||
|
||||
bool isLocked = false;
|
||||
_lock.Enter(ref isLocked);
|
||||
|
||||
Participants--;
|
||||
if (Participants == 0)
|
||||
{
|
||||
HasParticipants = false;
|
||||
}
|
||||
|
||||
if (isLocked)
|
||||
{
|
||||
_lock.Exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ThrowNoMoreParticipants()
|
||||
{
|
||||
throw new InvalidOperationException("There are no more participants. The operation is not allowed");
|
||||
}
|
||||
|
||||
public BarrierSlimmer()
|
||||
{
|
||||
_lock = new(false);
|
||||
}
|
||||
|
||||
public BarrierSlimmer(int participants)
|
||||
{
|
||||
_lock = new(false);
|
||||
Participants = participants;
|
||||
HasParticipants = participants > 0;
|
||||
}
|
||||
|
||||
public static BarrierSlimmer Create(int participants)
|
||||
{
|
||||
var result = _defaultPool.Get();
|
||||
result.Participants = participants;
|
||||
result.HasParticipants = participants > 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var assignedPool = _assignedPool;
|
||||
_assignedPool = null;
|
||||
assignedPool?.Return(this);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void SignalAndWait()
|
||||
{
|
||||
RemoveParticipant();
|
||||
|
||||
//if (!HasParticipants)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
//if (!HasParticipants)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
//if (!HasParticipants)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
// SpinWait.SpinUntil(() => HasParticipants);
|
||||
var waitSpinner = new SpinWait();
|
||||
while (HasParticipants)
|
||||
{
|
||||
waitSpinner.SpinOnce(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace Recyclable.Collections.Parallel
|
||||
{
|
||||
public sealed class ManualResetEventSlimmer
|
||||
{
|
||||
internal bool _isSet;
|
||||
public bool IsSet => _isSet;
|
||||
internal bool _returned;
|
||||
|
||||
public ManualResetEventSlimmer()
|
||||
{
|
||||
}
|
||||
|
||||
public ManualResetEventSlimmer(bool initialState)
|
||||
{
|
||||
_isSet = initialState;
|
||||
}
|
||||
|
||||
public void Set()
|
||||
{
|
||||
_isSet = true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_isSet = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_returned)
|
||||
{
|
||||
_returned = true;
|
||||
ManualResetEventSlimmerPool.Shared.Return(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
|
||||
namespace Recyclable.Collections.Parallel
|
||||
{
|
||||
public static class ManualResetEventSlimmerPool
|
||||
{
|
||||
public static readonly SpinLock _updateLock = new(false);
|
||||
public static readonly ObjectPool<ManualResetEventSlimmer> Shared = new DefaultObjectPool<ManualResetEventSlimmer>(new DefaultPooledObjectPolicy<ManualResetEventSlimmer>());
|
||||
|
||||
public static ManualResetEventSlimmer Create(bool initialState)
|
||||
{
|
||||
bool lockTaken = false;
|
||||
_updateLock.Enter(ref lockTaken);
|
||||
ManualResetEventSlimmer result = Shared.Get();
|
||||
if (lockTaken)
|
||||
{
|
||||
_updateLock.Exit(false);
|
||||
}
|
||||
|
||||
result._returned = false;
|
||||
if (result._isSet != initialState)
|
||||
{
|
||||
result._isSet = initialState;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace Recyclable.Collections.Parallel
|
||||
{
|
||||
public sealed class ParallelSynchronizationContext : IDisposable
|
||||
{
|
||||
public readonly ManualResetEventSlimmer ItemFoundSignal;
|
||||
public readonly Barrier AllDoneSignal;
|
||||
public long FoundItemIndex;
|
||||
public Exception? Exception;
|
||||
internal bool _returned;
|
||||
|
||||
public ParallelSynchronizationContext()
|
||||
{
|
||||
ItemFoundSignal = ManualResetEventSlimmerPool.Create(false);
|
||||
AllDoneSignal = new(0);
|
||||
}
|
||||
|
||||
public ParallelSynchronizationContext(int participantCount)
|
||||
{
|
||||
ItemFoundSignal = ManualResetEventSlimmerPool.Create(false);
|
||||
AllDoneSignal = new(participantCount);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_returned)
|
||||
{
|
||||
_returned = true;
|
||||
ParallelSynchronizationContextPool.Shared.Return(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemFoundSignal.Dispose();
|
||||
AllDoneSignal.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
|
||||
namespace Recyclable.Collections.Parallel
|
||||
{
|
||||
public static class ParallelSynchronizationContextPool
|
||||
{
|
||||
private static readonly SpinLock _updateLock = new(false);
|
||||
public static readonly ObjectPool<ParallelSynchronizationContext> Shared = new DefaultObjectPool<ParallelSynchronizationContext>(new DefaultPooledObjectPolicy<ParallelSynchronizationContext>());
|
||||
|
||||
public static ParallelSynchronizationContext GetWithOneParticipant()
|
||||
{
|
||||
bool lockTaken = false;
|
||||
_updateLock.Enter(ref lockTaken);
|
||||
var context = Shared.Get();
|
||||
if (lockTaken)
|
||||
{
|
||||
_updateLock.Exit(false);
|
||||
}
|
||||
|
||||
if (context.ItemFoundSignal._isSet)
|
||||
{
|
||||
context.ItemFoundSignal.Reset();
|
||||
}
|
||||
|
||||
switch (context.AllDoneSignal.ParticipantsRemaining)
|
||||
{
|
||||
case > 1:
|
||||
context.AllDoneSignal.RemoveParticipants(context.AllDoneSignal.ParticipantsRemaining - 1);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
context.AllDoneSignal.AddParticipant();
|
||||
break;
|
||||
}
|
||||
|
||||
if (context.Exception != null)
|
||||
{
|
||||
context.Exception = null;
|
||||
}
|
||||
|
||||
if (context.FoundItemIndex >= 0)
|
||||
{
|
||||
context.FoundItemIndex = -1L;
|
||||
}
|
||||
|
||||
context._returned = false;
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user