Skip to content

Commit 3cafd60

Browse files
Wi1l-B0tJim8y
andauthored
[Optimzie]: remove AsParallel in Cache (#3846)
* Optimzie: remove AsParallel in Cache * add benchmark --------- Co-authored-by: Jimmy <[email protected]>
1 parent 7fac685 commit 3cafd60

File tree

2 files changed

+113
-3
lines changed

2 files changed

+113
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright (C) 2015-2025 The Neo Project.
2+
//
3+
// Benchmarks.Cache.cs file belongs to the neo project and is free
4+
// software distributed under the MIT software license, see the
5+
// accompanying file LICENSE in the main directory of the
6+
// repository or http://www.opensource.org/licenses/mit-license.php
7+
// for more details.
8+
//
9+
// Redistribution and use in source and binary forms with or without
10+
// modifications are permitted.
11+
12+
using BenchmarkDotNet.Attributes;
13+
using Neo.IO.Caching;
14+
using System.Collections.Generic;
15+
using System.Diagnostics;
16+
using System.Linq;
17+
18+
namespace Neo.Benchmarks
19+
{
20+
class BenchmarkFIFOCache : FIFOCache<long, long>
21+
{
22+
public BenchmarkFIFOCache(int maxCapacity) : base(maxCapacity) { }
23+
24+
protected override long GetKeyForItem(long item) => item;
25+
}
26+
27+
public class Benchmarks_Cache
28+
{
29+
private readonly BenchmarkFIFOCache _cache = new(100);
30+
private readonly int _iterationCount = 1000;
31+
private readonly int _cacheSize = 100;
32+
33+
[Params(1000, 10000)]
34+
public int OperationCount { get; set; }
35+
36+
[GlobalSetup]
37+
public void Setup()
38+
{
39+
// Initialize cache with some data
40+
for (int i = 0; i < _cacheSize; i++)
41+
{
42+
_cache.Add(i);
43+
}
44+
}
45+
46+
[Benchmark]
47+
public void FIFOCacheAdd()
48+
{
49+
for (int i = 0; i < _iterationCount; i++)
50+
{
51+
_cache.Add(i);
52+
}
53+
}
54+
55+
[Benchmark]
56+
public void FIFOCacheContains()
57+
{
58+
for (long i = 0; i < _iterationCount; i++)
59+
{
60+
var ok = _cache.TryGet(i % _cacheSize, out _);
61+
Debug.Assert(ok);
62+
}
63+
}
64+
65+
[Benchmark]
66+
public void CachePerformanceWithoutParallel()
67+
{
68+
// Simulating the optimized version (current implementation)
69+
var dictionary = GetSampleDictionary(OperationCount);
70+
var removedCount = dictionary.Count - _cacheSize + 1;
71+
72+
foreach (var toDelete in dictionary.Values.OrderBy(p => p.Time).Take(removedCount))
73+
{
74+
// Simulate removal
75+
_ = toDelete;
76+
}
77+
}
78+
79+
[Benchmark]
80+
public void CachePerformanceWithParallel()
81+
{
82+
// Simulating the previous version with AsParallel
83+
var dictionary = GetSampleDictionary(OperationCount);
84+
85+
foreach (var item_del in dictionary.Values.AsParallel().OrderBy(p => p.Time).Take(dictionary.Count - _cacheSize + 1))
86+
{
87+
// Simulate removal
88+
_ = item_del;
89+
}
90+
}
91+
92+
private Dictionary<long, CacheItem> GetSampleDictionary(int count)
93+
{
94+
var dictionary = new Dictionary<long, CacheItem>();
95+
for (long i = 0; i < count; i++)
96+
{
97+
dictionary[i] = new CacheItem(i, i);
98+
}
99+
return dictionary;
100+
}
101+
102+
// Sample class to simulate the CacheItem for benchmarking
103+
private class CacheItem(long key, long value)
104+
{
105+
public readonly long Key = key;
106+
public readonly long Value = value;
107+
public readonly System.DateTime Time = System.DateTime.UtcNow.AddMilliseconds(-key); // Staggered times
108+
}
109+
}
110+
}

src/Neo.IO/Caching/Cache.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ private void AddInternal(TKey key, TValue item)
9393
{
9494
if (InnerDictionary.Count >= _max_capacity)
9595
{
96-
//TODO: Perform a performance test on the PLINQ query to determine which algorithm is better here (parallel or not)
97-
foreach (var item_del in InnerDictionary.Values.AsParallel().OrderBy(p => p.Time).Take(InnerDictionary.Count - _max_capacity + 1))
96+
var removedCount = InnerDictionary.Count - _max_capacity + 1;
97+
foreach (var toDelete in InnerDictionary.Values.OrderBy(p => p.Time).Take(removedCount))
9898
{
99-
RemoveInternal(item_del);
99+
RemoveInternal(toDelete);
100100
}
101101
}
102102
InnerDictionary.Add(key, new CacheItem(key, item));

0 commit comments

Comments
 (0)