ದೊಡ್ಡ ಬಫರ್ಗಳಲ್ಲಿ (large buffers) ವಿರಳವಾದ ವಿಭಜಕಗಳನ್ನು (sparse delimiters) ಸ್ಕ್ಯಾನ್ ಮಾಡುವಾಗ, .NET 10 ನಲ್ಲಿ SearchValues<T> ಕೊನೆಗೂ ಗಮನಾರ್ಹ ಪ್ರಯೋಜನವನ್ನು ತೋರಿಸುತ್ತಿದೆ. 32 MB ಪೇಲೋಡ್ನಲ್ಲಿ SearchValues 3.3 ms ನಲ್ಲಿ ಪೂರ್ಣಗೊಂಡರೆ, IndexOfAny 5.6 ms ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ.
SearchValues ಏಕೆ ಪರಿಚಯಿಸಲ್ಪಟ್ಟಿತು
ಅಕ್ಷರಗಳ ಅಥವಾ ಬೈಟ್ಗಳ ಗುಂಪನ್ನು ಮೊದಲೇ ಲೆಕ್ಕಹಾಕಲು (pre-compute) ಮತ್ತು ಆ ಗುಂಪಿಗೆ ಅತ್ಯಂತ ವೇಗವಾದ ಸ್ಕ್ಯಾನಿಂಗ್ ಅಲ್ಗಾರಿದಮ್ ಅನ್ನು ರನ್ಟೈಮ್ ಆಯ್ಕೆ ಮಾಡಲು .NET 8 SearchValues<T> ಅನ್ನು ಪರಿಚಯಿಸಿತು. ಒಮ್ಮೆ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ರಚಿಸಿ, ನಂತರ ಸ್ಪಾನ್ನಲ್ಲಿ (span) ಯಾವುದೇ ಮೌಲ್ಯಗಳನ್ನು ಹುಡುಕಬೇಕಾದಾಗ ಅದನ್ನು ಮರುಬಳಕೆ ಮಾಡಿ. ರನ್ಟೈಮ್ ವೆಕ್ಟರೈಸ್ಡ್ ಇನ್ಸ್ಟ್ರಕ್ಷನ್ಗಳು (vectorized instructions), ಬ್ರಾಂಚ್-ಫ್ರೀ ಲೂಪ್ಗಳು (branch-free loops) ಅಥವಾ ಇತರ ಲೋ-ಲೆವೆಲ್ ತಂತ್ರಗಳನ್ನು ಬಳಸಬಹುದು, ಇವುಗಳನ್ನು ಹೆಚ್ಚಿನ ಪ್ರಯತ್ನವಿಲ್ಲದೆ ಕೈಬರಹದ ಪರ್ಯಾಯ ವಿಧಾನಗಳು égal ಮಾಡಲಾರವು.
ಮುಖ್ಯವಾದ ಬೆಂಚ್ಮಾರ್ಕ್ಗಳು
ಚರ್ಚೆಯನ್ನು ಹುಟ್ಟುಹಾಕಿದ ಪರೀಕ್ಷೆಗಳು ಐದು ವಿಭಜಕ ಅಕ್ಷರಗಳನ್ನು ಹೊಂದಿರುವ 32 MB ಬಫರ್ ಅನ್ನು ಬಳಸಿದವು. .NET 10 ನಲ್ಲಿ ಮೂರು ವಿಧಾನಗಳ ಸಮಯವನ್ನು ಅಳೆಯಲಾಯಿತು:
- IndexOfAny(char[]) – 10.2 ms
- ಸ್ಪಾನ್ ಮೇಲೆ ಮ್ಯಾನುಯಲ್ foreach ಲೂಪ್ – 19.4 ms
- SearchValues
– 9.7 ms
SearchValues ಬಿಲ್ಟ್-ಇನ್ IndexOfAny ಅನ್ನು ಕೇವಲ ಅರ್ಧ ಮಿಲಿಸೆಕೆಂಡ್ ಅಂತರದಲ್ಲಿ ಹಿಂದಿಕ್ಕಿತು. ಇದು ಫೋರಂಗಳಲ್ಲಿ ಚರ್ಚೆಯಾಗುವಂತಹ "ಐದು ಪಟ್ಟು ವೇಗ" ಎಂಬ ನಾಟಕೀಯ ಹೇಳಿಕೆಯಲ್ಲ; ಆಧುನಿಕ .NET ಈಗಾಗಲೇ ಸಣ್ಣ ಗುಂಪುಗಳಿಗಾಗಿ IndexOfAny ಅನ್ನು ಆಪ್ಟಿಮೈಸ್ ಮಾಡಿದೆ, ಇದರಿಂದ ಅಂತರವು ಕಡಿಮೆಯಾಗಿದೆ.
ವಿಭಜಕಗಳು ವಿರಳವಾಗಿದ್ದಾಗ—ಪ್ರತಿ 60 ಬೈಟ್ಗಳ ಬದಲಿಗೆ ಪ್ರತಿ 40 KB ಗೆ ಒಮ್ಮೆ ಕಾಣಿಸಿಕೊಂಡಾಗ—ಪರಿಣಾಮ ಬದಲಾಗುತ್ತದೆ:
- IndexOfAny(char[]) – 5.6 ms
- SearchValues
– 3.3 ms
ಈಗ SearchValues 1.7 × ವೇಗವಾಗಿದೆ ಏಕೆಂದರೆ ಎಂಜಿನ್ ವೆಕ್ಟರೈಸ್ಡ್ ಹಂತಗಳೊಂದಿಗೆ ಹೊಂದಿಕೆಯಾಗದ ದತ್ತಾಂಶದ ದೀರ್ಘ ಪಟ್ಟಿಯ ಮೂಲಕ ವೇಗವಾಗಿ ಚಲಿಸುತ್ತದೆ, ಆದರೆ IndexOfAny ಕಡಿಮೆ ತೀವ್ರತೆಯ ಹಾದಿಯನ್ನು ಅನುಸರಿಸುತ್ತದೆ.
ಗುಪ್ತ ವೆಚ್ಚ (The hidden cost)
SearchValues ಉಚಿತವಲ್ಲ. ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ರಚಿಸುವುದು ಮೆಮೊರಿಯನ್ನು ಹಂಚಿಕೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ಆಂತರಿಕ ಲುಕ್ಅಪ್ ಟೇಬಲ್ಗಳನ್ನು (lookup tables) ನಿರ್ಮಿಸುತ್ತದೆ. ನೀವು ಪ್ರತಿ ಮೆಥಡ್ ಕಾಲ್ನಲ್ಲಿ ಇದನ್ನು ಇನ್ಸ್ಟಾಂಟಿಯೇಟ್ ಮಾಡಿದರೆ, ಅದರ ಓವರ್ಹೆಡ್ (overhead) ರನ್ಟೈಮ್ ಲಾಭಕ್ಕಿಂತ ದೊಡ್ಡದಾಗಿರುತ್ತದೆ. ಸಣ್ಣ ಸಾಲುಗಳ ಮೇಲೆ ಒಂದು ಮಿಲಿಯನ್ ಬಾರಿ ಸ್ಕ್ಯಾನಿಂಗ್ ರೂಟೀನ್ ಅನ್ನು ಕರೆದ ಬೆಂಚ್ಮಾರ್ಕ್ ಈ ಕೆಳಗಿನಂತೆ ತೋರಿಸಿದೆ:
- Static (ಮರುಬಳಕೆ ಮಾಡಿದ) SearchValues – ಒಟ್ಟು 25.1 ms
- Per-call SearchValues – ಒಟ್ಟು 70.2 ms
ಪ್ರತಿ ಕಾಲ್ಗೆ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ರಚಿಸುವುದು, SearchValues ಅನ್ನು ಬಳಸದಿದ್ದಕ್ಕಿಂತ ಇಡೀ ಪ್ರಕ್ರಿಯೆಯನ್ನು ಮೂರು ಪಟ್ಟು ನಿಧಾನಗೊಳಿಸುತ್ತದೆ. ಇನ್ಸ್ಟೆನ್ಸ್ ಅನ್ನು static readonly ಫೀಲ್ಡ್ನಲ್ಲಿ ಸಂಗ್ರಹಿಸಿ ಅಥವಾ ಕಾಲ್ಗಳಾದ್ಯಂತ ಮರುಬಳಕೆ ಮಾಡಿ.
SearchValues ಅನ್ನು ಯಾವಾಗ ಬಳಸಬೇಕು
- ದೊಡ್ಡ ಇನ್ಪುಟ್ಗಳು, ಕಡಿಮೆ ಹೊಂದಾಣಿಕೆಗಳು – ಸ್ಕ್ಯಾನರ್ ವಿಭಜಕವನ್ನು ತಲುಪದೆ ದೀರ್ಘ ಅವಧಿಯನ್ನು ದಾಟಬಹುದಾದಾಗ ವೆಕ್ಟರೈಸ್ಡ್ ಹಾದಿಯು ಅತ್ಯುತ್ತಮವಾಗಿ ಕೆಲಸ ಮಾಡುತ್ತದೆ.
- ಅದೇ ಸೆಟ್ನೊಂದಿಗೆ ಪದೇ ಪದೇ ಸ್ಕ್ಯಾನ್ ಮಾಡುವುದು – ಒಂದೇ ಅಕ್ಷರಗಳನ್ನು ಅನೇಕ ಬಾರಿ ಹುಡುಕುತ್ತಿದ್ದರೆ, ಒಮ್ಮೆ ಮಾಡುವ ಸೆಟಪ್ ಲಾಭದಾಯಕವಾಗಿರುತ್ತದೆ.
IndexOfAny ನಲ್ಲೇ ಇರಬೇಕಾದಾಗ
- ಸಣ್ಣ ಸ್ಟ್ರಿಂಗ್ಗಳು ಅಥವಾ ಹೆಚ್ಚಿನ ಹೊಂದಾಣಿಕೆಗಳು – ಹೆಚ್ಚುವರಿ ಸೆಟಪ್ ವೆಚ್ಚವು ಸಣ್ಣ ವೇಗದ ಲಾಭಕ್ಕಿಂತ ಹೆಚ್ಚಾಗಿರುತ್ತದೆ.
- ಈಗಾಗಲೇ IndexOfAny ಬಳಸುತ್ತಿರುವ ಕೋಡ್ – ಆಧುನಿಕ .NET ನ ಇಂಪ್ಲಿಮೆಂಟೇಶನ್ ಈಗಾಗಲೇ ಸಣ್ಣ ಅಕ್ಷರಗಳ ಗುಂಪುಗಳಿಗಾಗಿ ಉತ್ತಮವಾಗಿ ಟ್ಯೂನ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ, ಆದ್ದರಿಂದ
SearchValuesಅನ್ನು ಬದಲಾಯಿಸುವುದು ಹೆಚ್ಚಿನ ಬದಲಾವಣೆ ತರದಿರಬಹುದು.
ಸಾಮಾನ್ಯ ತಪ್ಪುಗಳು
- Hot loops ನಲ್ಲಿ ನಿರ್ಮಾಣವನ್ನು ಸೇರಿಸುವುದು – ಇದು ಮೇಲೆ ತೋರಿಸಿದಂತೆ ಮೂರು ಪಟ್ಟು ನಿಧಾನಗತಿಯಗೆ ಕಾರಣವಾಗುತ್ತದೆ.
- ಮ್ಯಾನುಯಲ್ ಲೂಪ್ಗಳ ಮೂಲಕ ರನ್ಟೈಮ್ ಅನ್ನು "ಸ್ಮಾರ್ಟ್" ಮಾಡಲು ಪ್ರಯತ್ನಿಸುವುದು – ಮ್ಯಾನುಯಲ್ foreach ಆವೃತ್ತಿಯು ಎರಡೂ ಬಿಲ್ಟ್-ಇನ್ ವಿಧಾನಗಳಿಗಿಂತ ಎರಡು ಪಟ್ಟು ನಿಧಾನವಾಗಿತ್ತು, ಇದು SIMD ಇನ್ಸ್ಟ್ರಕ್ಷನ್ಗಳ ಬಗ್ಗೆ ಆಳವಾದ ಜ್ಞಾನವಿಲ್ಲದೆ .NET ಲೈಬ್ರರಿಗಳನ್ನು ಸೋಲಿಸುವುದು ಕಷ್ಟ ಎಂದು ದೃಢಪಡಿಸುತ್ತದೆ.
- ಎಲ್ಲಾ ಕಡೆ ವೇಗ ಹೆಚ್ಚಾಗುತ್ತದೆ ಎಂದು ಭಾವಿಸುವುದು – ದಟ್ಟವಾದ ದತ್ತಾಂಶದ ಮೇಲೆ (dense data) ಸಿಕ್ಕ ಅರ್ಧ ಮಿಲಿಸೆಕೆಂಡ್ ಗೆಲುವು,
SearchValuesಎಂಬುದು ಎಲ್ಲದಕ್ಕೂ ಅನ್ವಯವಾಗುವ "ಚೀಟ್ ಕೋಡ್" ಅಲ್ಲ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸುತ್ತದೆ; ಇದರ ಪ್ರಯೋಜನಗಳು ದತ್ತಾಂಶದ ಮೇಲೆ ಅವಲಂಬಿತವಾಗಿವೆ.
ಸಾರಾಂಶ (Takeaway)
ನೀವು ವಿರಳವಾದ ಅಕ್ಷರಗಳಿಗಾಗಿ ದೊಡ್ಡ ಬಫರ್ಗಳನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡುವಾಗ ಮತ್ತು ಒಮ್ಮೆ ಮಾಡುವ ನಿರ್ಮಾಣ ವೆಚ್ಚವನ್ನು ಭರಿಸಬಲ್ಲಾಗಿದ್ದಾಗ ಮಾತ್ರ SearchValues<T> ಸ್ಪಷ್ಟ ಪ್ರಯೋಜನವನ್ನು ನೀಡುತ್ತದೆ. ಹೆಚ್ಚಿನ ದೈನಂದಿನ ಸ್ಟ್ರಿಂಗ್-ಸರ್ಚ್ ಸನ್ನಿವೇಶಗಳಿಗೆ—ಸಣ್ಣ ಇನ್ಪುಟ್ಗಳು, ಪದೇ ಪದೇ ಹೊಂದಾಣಿಕೆಗಳು ಅಥವಾ ಈಗಾಗಲೇ IndexOfAny ಮೇಲೆ ಅವಲಂಬಿತವಾಗಿರುವ ಕೋಡ್—ಬಿಲ್ಟ್-ಇನ್ ವಿಧಾನವೇ ಸರಳ ಮತ್ತು ವೇಗವಾದ ಆಯ್ಕೆಯಾಗಿ ಉಳಿಯುತ್ತದೆ. SearchValues ಅನ್ನು ಆಯ್ದುಕೊಂಡು ಬಳಸಿ, ಇನ್ಸ್ಟೆನ್ಸ್ ಅನ್ನು ಕ್ಯಾಶ್ (cache) ಮಾಡಿ, ಆಗ ನೀವು ಗುಪ್ತ ದಂಡವನ್ನು ತಪ್ಪಿಸಿ ನಿಜವಾದ ಕಾರ್ಯಕ್ಷಮತೆಯ ಲಾಭವನ್ನು ಪಡೆಯಬಹುದು.
ಮೂಲ ಕೋಡ್ ಮತ್ತು ಪೂರ್ಣ ಪರೀಕ್ಷಾ ಸೂಟ್: https://dev.to/ssukhpinder/when-searchvalues-actually-pays-off-310l
