Ik heb een set met daarin ~ 70.000 verschillende Int32's (dwars door elkaar!). Deze Int32's wil ik verdelen in buckets, zodat er zo min mogelijk 'lege ruimtes' in zitten. Voorbeeld:
De adressen hierin zijn pointers. Ik wil dus de adressen 0x01, 0x02, 0x04, 0x16 etc. lezen. Omdat per item lezen verschrikkelijk duur is, ga ik bufferen.
Als ik nu 0x01 t/m 0x20 lees, lees ik heel veel bytes voor niets.
met een maximale lege ruimte van '5' worden dit 2 buckets met daarin:
Nu doe ik 2 reads, 1 keer van 0x01 t/m 0x04, en een keer van 0x16 t/m 0x20. Ergo: sneller. Zeker als de ruimte tussen buckets gewoon 10 MB ofzo is.
Ik heb hiervoor een vrij naieve implementatie die het volgende doet:
- Sorteer lijst van laag - hoog
- Doorloop lijst
- Als verschil tussen vorige en huidige > 0x10000 -> nieuwe bucket
- Als bucketsize > 16 MB -> nieuwe bucket
- Voeg toe aan huidige bucket
Nadeel van deze approach:
- Sorteren van 70.000 int's die dwars door elkaar staan is érg duur (80% van CPU time ongeveer)
Ik heb naar Quick- en Mergesort's implementaties gekeken (ook parallel) maar vond geen snellere dan de standaard 'OrderBy' in Linq.
Weet iemand iets snellers? De buckets hoeven niet een 'perfecte' size te hebben ofzo, als ik hier wat tijdswinst pak, wil ik best meer buckets lezen. Ik accepteer ook dat er een aantal adressen in geen enkele bucket vallen (0,05% max. Daarna wordt het traag.).
En voor those interested, het is hier voor: http://code.google.com/p/scoutframeworkfm2009/
code:
1
| source = 1, 2, 4, 16, 17, 20 |
De adressen hierin zijn pointers. Ik wil dus de adressen 0x01, 0x02, 0x04, 0x16 etc. lezen. Omdat per item lezen verschrikkelijk duur is, ga ik bufferen.
Als ik nu 0x01 t/m 0x20 lees, lees ik heel veel bytes voor niets.
met een maximale lege ruimte van '5' worden dit 2 buckets met daarin:
code:
1
2
| bucket1 = 1, 2, 4 bucket2 = 16, 17, 20 |
Nu doe ik 2 reads, 1 keer van 0x01 t/m 0x04, en een keer van 0x16 t/m 0x20. Ergo: sneller. Zeker als de ruimte tussen buckets gewoon 10 MB ofzo is.
Ik heb hiervoor een vrij naieve implementatie die het volgende doet:
- Sorteer lijst van laag - hoog
- Doorloop lijst
- Als verschil tussen vorige en huidige > 0x10000 -> nieuwe bucket
- Als bucketsize > 16 MB -> nieuwe bucket
- Voeg toe aan huidige bucket
Nadeel van deze approach:
- Sorteren van 70.000 int's die dwars door elkaar staan is érg duur (80% van CPU time ongeveer)
Ik heb naar Quick- en Mergesort's implementaties gekeken (ook parallel) maar vond geen snellere dan de standaard 'OrderBy' in Linq.
Weet iemand iets snellers? De buckets hoeven niet een 'perfecte' size te hebben ofzo, als ik hier wat tijdswinst pak, wil ik best meer buckets lezen. Ik accepteer ook dat er een aantal adressen in geen enkele bucket vallen (0,05% max. Daarna wordt het traag.).
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| // memoryAddressList bevat circa 70.000 objecten // maxBufferSize is 16 * 1024 * 1024 public static List<List<int>> SplitMemoryAddressesIntoBuffer(List<Int32> memoryAddressesList, int maxBufferSize) { // sorteer eerst memoryAddresses = memoryAddressesList.OrderBy(a => a).ToArray(); // bepaal de laagste waarde int lowestPointer = memoryAddresses.First(); // bepaalde hoogste waarde int highestPointer = memoryAddresses.Last(); //holder voor mijn buckets List<List<int>> memoryAddressBatches = new List<List<int>>(); // initialiseer wat waardes var currentAddressList = new List<int>(); int previousAddress = lowestPointer - 1; // hierin stop ik laatst verwerkte item int lowestThisBatch = lowestPointer; // dit om te bepalen of we naar nieuwe bucket moeten // doorloop de hele lijst foreach(var mem in memoryAddresses) { // maak nieuwe bucket aan als verschil > 0x10000 of als de bucket groter is dan de maxSize if(mem - previousAddress > 0x10000 || mem - lowestThisBatch > maxBufferSize) { memoryAddressBatches.Add(currentAddressList); lowestThisBatch = mem; currentAddressList = new List<int>(); } // voeg toe aan huidige lijst currentAddressList.Add(mem); previousAddress = mem; } // voeg laatste bucket toe aan output memoryAddressBatches.Add(currentAddressList); #endregion // lege leeg gooien var batches = memoryAddressBatches.Where(m=>m.Count > 0).ToList(); return batches; } |
En voor those interested, het is hier voor: http://code.google.com/p/scoutframeworkfm2009/