RecyclableList.IndexOf performance improvements.

This commit is contained in:
mlemanczyk committed 2023-05-25 20:02:50 +02:00
1 parent 21c82d80a2
commit db8ee72c59
2 files changed
+71 -18

No files matched your search

@@ -3,6 +3,10 @@ namespace Recyclable.Collections.Parallel
public sealed class IndexOfSynchronizationContext public sealed class IndexOfSynchronizationContext
{ {
private readonly SpinWait _participantsSpinWait = new(); private readonly SpinWait _participantsSpinWait = new();
private readonly SpinLock _participantsSpinLock = new(false);
private readonly SpinLock _indexOfSpinLock = new(false);
private bool _indexOfLockTaken;
internal bool _isItemFound; internal bool _isItemFound;
internal int _participants; internal int _participants;
@@ -10,12 +14,29 @@ namespace Recyclable.Collections.Parallel
public void AddParticipant() public void AddParticipant()
{ {
_ = Interlocked.Increment(ref _participants); bool lockTaken = false;
_participantsSpinLock.Enter(ref lockTaken);
_participants++;
if (lockTaken)
{
_participantsSpinLock.Exit(false);
}
} }
public void AddParticipants(int newParticipants) public void AddParticipants(int newParticipants)
{ {
_ = Interlocked.Add(ref _participants, newParticipants); bool lockTaken = false;
_participantsSpinLock.Enter(ref lockTaken);
_participants += newParticipants;
if (lockTaken)
{
_participantsSpinLock.Exit(false);
}
}
public void Lock()
{
_indexOfSpinLock.Enter(ref _indexOfLockTaken);
} }
public void RemoveParticipants(int participantsToRemove) public void RemoveParticipants(int participantsToRemove)
@@ -25,7 +46,13 @@ namespace Recyclable.Collections.Parallel
ThrowNotEnoughParticipants(); ThrowNotEnoughParticipants();
} }
_ = Interlocked.Add(ref _participants, -participantsToRemove); bool lockTaken = false;
_participantsSpinLock.Enter(ref lockTaken);
_participants -= participantsToRemove;
if (lockTaken)
{
_participantsSpinLock.Exit(false);
}
} }
public void RemoveParticipant() public void RemoveParticipant()
@@ -35,7 +62,13 @@ namespace Recyclable.Collections.Parallel
ThrowNoMoreParticipants(); ThrowNoMoreParticipants();
} }
_ = Interlocked.Decrement(ref _participants); bool lockTaken = false;
_participantsSpinLock.Enter(ref lockTaken);
_participants--;
if (lockTaken)
{
_participantsSpinLock.Exit(false);
}
} }
public void SignalAndWait() public void SignalAndWait()
@@ -45,13 +78,28 @@ namespace Recyclable.Collections.Parallel
ThrowNoMoreParticipants(); ThrowNoMoreParticipants();
} }
_ = Interlocked.Decrement(ref _participants); bool lockTaken = false;
_participantsSpinLock.Enter(ref lockTaken);
_participants--;
if (lockTaken)
{
_participantsSpinLock.Exit(false);
}
while (_participants > 0) while (_participants > 0)
{ {
_participantsSpinWait.SpinOnce(); _participantsSpinWait.SpinOnce();
} }
} }
public void Unlock()
{
if (_indexOfLockTaken)
{
_indexOfSpinLock.Exit(false);
}
}
private static void ThrowNotEnoughParticipants() => throw new InvalidOperationException("Participant cannot be removed, because there are not enough participants."); private static void ThrowNotEnoughParticipants() => throw new InvalidOperationException("Participant cannot be removed, because there are not enough participants.");
private static void ThrowNoMoreParticipants() => throw new InvalidOperationException("Participant cannot be removed, because there are no more participants."); private static void ThrowNoMoreParticipants() => throw new InvalidOperationException("Participant cannot be removed, because there are no more participants.");
@@ -25,7 +25,9 @@ namespace Recyclable.Collections
else if (index >= 0) else if (index >= 0)
{ {
context._isItemFound = true; context._isItemFound = true;
_ = Interlocked.Exchange(ref context.FoundItemIndex, (blockIndex << list._blockSizePow2BitShift) + index); context.Lock();
context.FoundItemIndex = ((long)blockIndex << list._blockSizePow2BitShift) + index;
context.Unlock();
return; return;
} }
@@ -37,7 +39,9 @@ namespace Recyclable.Collections
else if (index >= 0) else if (index >= 0)
{ {
context._isItemFound = true; context._isItemFound = true;
_ = Interlocked.Exchange(ref context.FoundItemIndex, ((blockIndex + 1) << list._blockSizePow2BitShift) + index); context.Lock();
context.FoundItemIndex = ((long)(blockIndex + 1) << list._blockSizePow2BitShift) + index;
context.Unlock();
return; return;
} }
@@ -49,7 +53,9 @@ namespace Recyclable.Collections
else if (index >= 0) else if (index >= 0)
{ {
context._isItemFound = true; context._isItemFound = true;
_ = Interlocked.Exchange(ref context.FoundItemIndex, ((blockIndex + 2) << list._blockSizePow2BitShift) + index); context.Lock();
context.FoundItemIndex = ((long)(blockIndex + 2) << list._blockSizePow2BitShift) + index;
context.Unlock();
return; return;
} }
@@ -57,7 +63,9 @@ namespace Recyclable.Collections
if (!context._isItemFound && index >= 0) if (!context._isItemFound && index >= 0)
{ {
context._isItemFound = true; context._isItemFound = true;
_ = Interlocked.Exchange(ref context.FoundItemIndex, ((blockIndex + 3) << list._blockSizePow2BitShift) + index); context.Lock();
context.FoundItemIndex = ((long)(blockIndex + 3) << list._blockSizePow2BitShift) + index;
context.Unlock();
} }
} }
catch (Exception e) catch (Exception e)
@@ -87,7 +95,9 @@ namespace Recyclable.Collections
if (!context._isItemFound && index >= 0) if (!context._isItemFound && index >= 0)
{ {
context._isItemFound = true; context._isItemFound = true;
_ = Interlocked.Exchange(ref context.FoundItemIndex, (blockIndex << list._blockSizePow2BitShift) + index); context.Lock();
context.FoundItemIndex = ((long)blockIndex << list._blockSizePow2BitShift) + index;
context.Unlock();
} }
} }
catch (Exception e) catch (Exception e)
@@ -176,7 +186,9 @@ namespace Recyclable.Collections
if (!context._isItemFound && itemIndex >= 0) if (!context._isItemFound && itemIndex >= 0)
{ {
context._isItemFound = true; context._isItemFound = true;
_ = Interlocked.Exchange(ref context.FoundItemIndex, ((long)blockIndex << list._blockSizePow2BitShift) + itemIndex); context.Lock();
context.FoundItemIndex = ((long)blockIndex << list._blockSizePow2BitShift) + itemIndex;
context.Unlock();
} }
} }
@@ -249,16 +261,9 @@ namespace Recyclable.Collections
} }
} }
//if (blockIndex == list._lastBlockWithData)
//{
itemIndex = list._nextItemIndex != 0 itemIndex = list._nextItemIndex != 0
? Array.IndexOf(memoryBlocksSpan[list._lastBlockWithData], item, 0, list._nextItemIndex) ? Array.IndexOf(memoryBlocksSpan[list._lastBlockWithData], item, 0, list._nextItemIndex)
: Array.IndexOf(memoryBlocksSpan[list._lastBlockWithData], item, 0, list._blockSize); : Array.IndexOf(memoryBlocksSpan[list._lastBlockWithData], item, 0, list._blockSize);
//}
//else
//{
// return RecyclableDefaults.ItemNotFoundIndexLong;
//}
return itemIndex >= 0 ? itemIndex + ((long)list._lastBlockWithData << list._blockSizePow2BitShift) : RecyclableDefaults.ItemNotFoundIndexLong; return itemIndex >= 0 ? itemIndex + ((long)list._lastBlockWithData << list._blockSizePow2BitShift) : RecyclableDefaults.ItemNotFoundIndexLong;
} }