SearchValues<T> ਅੰਤ ਵਿੱਚ .NET 10 ਵਿੱਚ ਵੱਡੇ ਬਫਰਾਂ (buffers) ਵਿੱਚ ਵਿਰਲ ਡਿਲੀਮੀਟਰਾਂ (sparse delimiters) ਦੀ ਖੋਜ ਕਰਨ ਵੇਲੇ ਇੱਕ ਮਾਪਣਯੋਗ ਫਾਇਦਾ ਦਿਖਾਉਂਦਾ ਹੈ, ਜਿੱਥੇ 32 MB ਪੇਲੋਡ (payload) 'ਤੇ SearchValues 3.3 ms ਵਿੱਚ ਪੂਰਾ ਹੋ ਜਾਂਦਾ ਹੈ, ਜਦੋਂ ਕਿ IndexOfAny ਨੂੰ 5.6 ms ਲੱਗਦੇ ਹਨ।
SearchValues ਕਿਉਂ ਆਇਆ
.NET 8 ਨੇ SearchValues<T> ਨੂੰ ਅੱਖਰਾਂ (ਜਾਂ ਬਾਈਟਾਂ) ਦੇ ਇੱਕ ਸਮੂਹ ਨੂੰ ਪਹਿਲਾਂ ਤੋਂ ਕੰਪਿਊਟ (pre-compute) ਕਰਨ ਲਈ ਪੇਸ਼ ਕੀਤਾ ਸੀ ਤਾਂ ਜੋ ਰਨਟਾਈਮ (runtime) ਉਸ ਸਮੂਹ ਲਈ ਸਭ ਤੋਂ ਤੇਜ਼ ਸਕੈਨਿੰਗ ਐਲਗੋਰਿਦਮ ਦੀ ਚੋਣ ਕਰ ਸਕੇ। ਆਬਜੈਕਟ ਨੂੰ ਇੱਕ ਵਾਰ ਬਣਾਓ, ਫਿਰ ਜਦੋਂ ਵੀ ਤੁਹਾਨੂੰ ਕਿਸੇ span ਵਿੱਚ ਕਿਸੇ ਵੀ ਮੁੱਲ (value) ਨੂੰ ਲੱਭਣ ਦੀ ਲੋੜ ਹੋਵੇ, ਤਾਂ ਇਸਦੀ ਦੁਬਾਰਾ ਵਰਤੋਂ ਕਰੋ। ਰਨਟਾਈਮ ਵੈਕਟੋਰਾਈਜ਼ਡ ਇੰਸਟ੍ਰਕਸ਼ਨਾਂ (vectorized instructions), ਬ੍ਰਾਂਚ-ਫ੍ਰੀ ਲੂਪਸ (branch-free loops), ਜਾਂ ਹੋਰ ਲੋ-ਲੈਵਲ ਤਰੀਕਿਆਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦਾ ਹੈ ਜਿਨ੍ਹਾਂ ਦਾ ਹੱਥ ਨਾਲ ਲਿਖੇ ਵਿਕਲਪ ਬਹੁਤ ਜ਼ਿਆਦਾ ਕੋਸ਼ਿਸ਼ ਤੋਂ ਬਿਨਾਂ ਮੁਕਾਬਲਾ ਨਹੀਂ ਕਰ ਸਕਦੇ।
ਮਹੱਤਵਪੂਰਨ ਬੈਂਚਮਾਰਕਸ (Benchmarks)
ਚਰਚਾ ਨੂੰ ਜਨਮ ਦੇਣ ਵਾਲੇ ਟੈਸਟਾਂ ਵਿੱਚ ਪੰਜ ਡਿਲੀਮੀਟਰ ਅੱਖਰਾਂ ਵਾਲਾ 32 MB ਬਫਰ ਵਰਤਿਆ ਗਿਆ ਸੀ। .NET 10 'ਤੇ ਤਿੰਨ ਤਰੀਕਿਆਂ ਦਾ ਸਮਾਂ ਮਾਪਿਆ ਗਿਆ:
- IndexOfAny(char[]) – 10.2 ms
- Span ਉੱਤੇ ਮੈਨੂਅਲ 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 × ਤੇਜ਼ ਹੈ ਕਿਉਂਕਿ ਇੰਜਣ ਵੈਕਟੋਰਾਈਜ਼ਡ ਕਦਮਾਂ ਨਾਲ ਗੈਰ-ਮੇਲ ਡੇਟਾ (non-matching data) ਦੇ ਲੰਬੇ ਹਿੱਸਿਆਂ ਵਿੱਚੋਂ ਤੇਜ਼ੀ ਨਾਲ ਲੰਘ ਜਾਂਦਾ ਹੈ, ਜਦੋਂ ਕਿ IndexOfAny ਘੱਟ ਹਮਲਾਵਰ (less aggressive) ਮਾਰਗ ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ।
ਲੁਕੀ ਹੋਈ ਕੀਮਤ
SearchValues ਮੁਫ਼ਤ ਨਹੀਂ ਹੈ। ਆਬਜੈਕਟ ਬਣਾਉਣ ਨਾਲ ਮੈਮੋਰੀ ਅਲਾਕੋਟ (allocate) ਹੁੰਦੀ ਹੈ ਅਤੇ ਅੰਦਰੂਨੀ ਲੁੱਕਅੱਪ ਟੇਬਲ (lookup tables) ਬਣਦੇ ਹਨ। ਜੇਕਰ ਤੁਸੀਂ ਹਰ ਮੈਥਡ ਕਾਲ 'ਤੇ ਇਸਨੂੰ ਇੰਸਟੈਂਸ਼ੀਏਟ (instantiate) ਕਰਦੇ ਹੋ, ਤਾਂ ਇਸਦਾ ਓਵਰਹੈੱਡ (overhead) ਕਿਸੇ ਵੀ ਰਨਟਾਈਮ ਫਾਇਦੇ ਨੂੰ ਖਤਮ ਕਰ ਦਿੰਦਾ ਹੈ। ਇੱਕ ਬੈਂਚਮਾਰਕ ਜਿਸਨੇ ਛੋਟੀਆਂ ਲਾਈਨਾਂ 'ਤੇ ਸਕੈਨਿੰਗ ਰੁਟੀਨ ਨੂੰ ਇੱਕ ਮਿਲੀਅਨ ਵਾਰ ਕਾਲ ਕੀਤਾ, ਉਸਨੇ ਦਿਖਾਇਆ:
- Static (ਦੁਬਾਰਾ ਵਰਤਿਆ ਗਿਆ) SearchValues – ਕੁੱਲ 25.1 ms
- Per-call SearchValues – ਕੁੱਲ 70.2 ms
ਹਰ ਕਾਲ ਲਈ ਆਬਜੈਕਟ ਬਣਾਉਣਾ ਪੂਰੀ ਪ੍ਰਕਿਰਿਆ ਨੂੰ SearchValues ਦੀ ਵਰਤੋਂ ਨਾ ਕਰਨ ਨਾਲੋਂ ਤਿੰਨ ਗੁਣਾ ਹੌਲੀ ਕਰ ਦਿੰਦਾ ਹੈ। ਇੰਸਟੈਂਸ ਨੂੰ static readonly ਫੀਲਡ ਵਿੱਚ ਸਟੋਰ ਕਰੋ ਜਾਂ ਕਾਲਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਵਰਤੋਂ ਕਰੋ।
SearchValues ਦੀ ਵਰਤੋਂ ਕਦੋਂ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ
- ਵੱਡੇ ਇਨਪੁੱਟ, ਘੱਟ ਮੈਚ – ਵੈਕਟੋਰਾਈਜ਼ਡ ਮਾਰਗ ਉਦੋਂ ਸ਼ਾਨਦਾਰ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਸਕੈਨਰ ਡਿਲੀਮੀਟਰ ਨਾਲ ਟਕਰਾਏ ਬਿਨਾਂ ਲੰਬੇ ਹਿੱਸਿਆਂ ਨੂੰ ਛੱਡ ਸਕਦਾ ਹੈ।
- ਇੱਕੋ ਸਮੂਹ ਨਾਲ ਵਾਰ-ਵਾਰ ਸਕੈਨ ਕਰਨਾ – ਜੇਕਰ ਇੱਕੋ ਅੱਖਰਾਂ ਦੀ ਬਹੁਤ ਵਾਰ ਖੋਜ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਇੱਕ ਵਾਰ ਦਾ ਸੈੱਟਅੱਪ ਫਾਇਦੇਮੰਦ ਹੁੰਦਾ ਹੈ।
IndexOfAny ਨਾਲ ਹੀ ਕਦੋਂ ਰਹਿਣਾ ਚਾਹੀਦਾ ਹੈ
- ਛੋਟੀਆਂ ਸਟ੍ਰਿੰਗਾਂ ਜਾਂ ਬਹੁਤ ਸਾਰੇ ਮੈਚ – ਵਾਧੂ ਸੈੱਟਅੱਪ ਦੀ ਕੀਮਤ ਮਾਮੂਲੀ ਰਫ਼ਤਾਰ ਦੇ ਫਾਇਦੇ ਨਾਲੋਂ ਵੱਧ ਹੁੰਦੀ ਹੈ।
- ਕੋਡ ਜੋ ਪਹਿਲਾਂ ਹੀ IndexOfAny ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ – ਆਧੁਨਿਕ .NET ਦਾ ਇੰਪਲੀਮੈਂਟੇਸ਼ਨ ਪਹਿਲਾਂ ਹੀ ਛੋਟੇ ਅੱਖਰਾਂ ਦੇ ਸਮੂਹਾਂ ਲਈ ਬਹੁਤ ਵਧੀਆ ਤਰੀਕੇ ਨਾਲ ਟਿਊਨ ਕੀਤਾ ਗਿਆ ਹੈ, ਇਸ ਲਈ
SearchValuesਨੂੰ ਲਗਾਉਣ ਨਾਲ ਕੋਈ ਵੱਡਾ ਫਰਕ ਨਹੀਂ ਪੈ ਸਕਦਾ।
ਆਮ ਗਲਤੀਆਂ
- Hot loops ਵਿੱਚ ਇਸਦੀ ਉਸਾਰੀ (construction) ਨੂੰ ਸ਼ਾਮਲ ਕਰਨਾ – ਇਸ ਨਾਲ ਉੱਪਰ ਦਿਖਾਇਆ ਗਿਆ ਤਿੰਨ ਗੁਣਾ ਦਾ ਸੁਸਤਪਨ ਆਉਂਦਾ ਹੈ।
- ਮੈਨੂਅਲ ਲੂਪਸ ਨਾਲ ਰਨਟਾਈਮ ਨੂੰ "ਚਲਾਕੀ ਨਾਲ ਹਰਾਉਣ" ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਨਾ – ਮੈਨੂਅਲ foreach ਵਰਜ਼ਨ ਦੋਵਾਂ ਬਿਲਟ-ਇਨ ਮੈਥਡਾਂ ਨਾਲੋਂ ਦੁੱਗਣਾ ਹੌਲੀ ਸੀ, ਜੋ ਇਹ ਪੁਸ਼ਟੀ ਕਰਦਾ ਹੈ ਕਿ SIMD ਇੰਸਟ੍ਰਕਸ਼ਨਾਂ ਦੇ ਡੂੰਘੇ ਗਿਆਨ ਤੋਂ ਬਿਨਾਂ .NET ਲਾਇਬ੍ਰੇਰੀਆਂ ਨੂੰ ਹਰਾਉਣਾ ਮੁਸ਼ਕਲ ਹੈ।
- ਯੂਨੀਵਰਸਲ ਸਪੀਡਅੱਪ ਦਾ ਅਸੁਮਾਨ ਕਰਨਾ – ਡੈਂਸ ਡੇਟਾ (dense data) 'ਤੇ ਅੱਧੇ ਮਿਲੀਸੈਕੰਡ ਦੀ ਜਿੱਤ ਇਹ ਸਾਬਤ ਕਰਦੀ ਹੈ ਕਿ
SearchValuesਕੋਈ ਯੂਨੀਵਰਸਲ ਚੀਟ ਕੋਡ ਨਹੀਂ ਹੈ; ਇਸਦੇ ਫਾਇਦੇ ਡੇਟਾ 'ਤੇ ਨਿਰਭਰ ਕਰਦੇ ਹਨ।
ਸਿੱਟਾ
SearchValues<T> ਸਿਰਫ ਉਦੋਂ ਹੀ ਸਪੱਸ਼ਟ ਫਾਇਦਾ ਦਿੰਦਾ ਹੈ ਜਦੋਂ ਤੁਸੀਂ ਵਿਰਲ ਅੱਖਰਾਂ ਲਈ ਵੱਡੇ ਬਫਰਾਂ ਨੂੰ ਸਕੈਨ ਕਰਦੇ ਹੋ ਅਤੇ ਇੱਕ ਵਾਰ ਦੀ ਉਸਾਰੀ ਦੀ ਕੀਮਤ ਅਦਾ ਕਰ ਸਕਦੇ ਹੋ। ਰੋਜ਼ਾਨਾ ਦੇ ਜ਼ਿਆਦਾਤਰ ਸਟ੍ਰਿੰਗ-ਸਰਚ ਸਥਿਤੀਆਂ ਲਈ—ਛੋਟੇ ਇਨਪੁੱਟ, ਵਾਰ-ਵਾਰ ਮੈਚ, ਜਾਂ ਕੋਡ ਜੋ ਪਹਿਲਾਂ ਹੀ IndexOfAny 'ਤੇ ਨਿਰਭਰ ਕਰਦਾ ਹੈ—ਬਿਲਟ-ਇਨ ਮੈਥਡ ਹੀ ਸਰਲ ਅਤੇ ਤੇਜ਼ ਚੋਣ ਬਣਿਆ ਰਹਿੰਦਾ ਹੈ। SearchValues ਦੀ ਚੋਣ ਚੁਣਵੀਆਂ ਸਥਿਤੀਆਂ ਵਿੱਚ ਕਰੋ, ਇੰਸਟੈਂਸ ਨੂੰ ਕੈਸ਼ (cache) ਕਰੋ, ਅਤੇ ਤੁਸੀਂ ਅਸਲ ਪ੍ਰਦਰਸ਼ਨ ਦਾ
