Make ToDictionary() selectors parallel. - #100590

Closed
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel
Closed

Make ToDictionary() selectors parallel.#100590
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel

Conversation

@lateapexearlyspeed

Copy link
Copy Markdown
Contributor

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 3, 2024
@jozkee

Copy link
Copy Markdown
Member

As stated in #96262 (comment), this will likely regress cases with a trivial key selector. @lateapexearlyspeed could you please provide a benchmark to see how bad it hits it so we can do an informed decision?

@jozkeejozkee added the needs-author-action An issue or pull request that requires more info or actions from the author. label May 20, 2024
@lateapexearlyspeed

Copy link
Copy Markdown
ContributorAuthor

@jozkee following is benchmark result of trivial key (and element) selector case. Toolchain in "runtime-main" is library before change and toolchain in "runtime" is library after change.

// * Summary *

BenchmarkDotNet=v0.13.1.1603-nightly, OS=Windows 10.0.22631
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
.NET SDK=8.0.202
[Host] : .NET 6.0.31 (6.0.3124.26714), X64 RyuJIT
Job-XVKCDM : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT
Job-ODFYHP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog IterationTime=250.0000 ms
MaxIterationCount=20 MinIterationCount=15 WarmupCount=1

MethodJobToolchainItemCountMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe142.00 ns9.363 ns10.782 ns35.46 ns32.76 ns62.01 ns1.000.000.0298--376 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe17,778.30 ns149.193 ns139.555 ns7,773.13 ns7,457.77 ns8,025.18 ns214.4327.420.6916--8,896 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10120.94 ns2.399 ns2.356 ns121.89 ns116.36 ns124.39 ns1.000.000.0765--960 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe108,034.68 ns190.599 ns219.495 ns8,038.56 ns7,658.90 ns8,423.41 ns66.692.110.7844--9,984 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe1001,054.74 ns94.978 ns109.377 ns1,025.83 ns905.00 ns1,335.60 ns1.000.000.60140.0073-7,576 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10010,700.76 ns295.269 ns328.191 ns10,768.11 ns10,152.59 ns11,369.07 ns10.201.001.5175--18,920 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10008,536.74 ns206.045 ns237.282 ns8,593.82 ns8,068.56 ns8,911.05 ns1.000.005.82940.6955-73,352 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe100045,359.53 ns1,780.828 ns2,050.804 ns44,628.87 ns42,440.57 ns50,316.83 ns5.310.228.32201.3587-104,118 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000175,304.48 ns5,273.794 ns6,073.309 ns174,695.64 ns166,454.45 ns186,023.27 ns1.000.00124.3351124.3351124.3351673,290 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000425,559.34 ns21,829.962 ns25,139.417 ns422,713.75 ns382,274.84 ns461,048.75 ns2.430.20131.2500131.2500123.4375848,901 B

[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}

@dotnet-policy-servicedotnet-policy-serviceBot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label May 29, 2024
@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -amd

usingSystem.Linq;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;BenchmarkRunner.Run<Tests>(args:args);publicclassTests{[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Select(i =>i).ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestWhereSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Where(i =>true).Select(i =>i).ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

@EgorBo

EgorBo commented May 29, 2024

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm]
it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args".
There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -intel -arm64

using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkRunner.Run<Tests>(args: args);
public class Tests
{
[Benchmark]
public void TestParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Select(i => i).ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestWhereSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Where(i => true).Select(i => i).ToDictionary(i => i, i => i);
}
[Params(1, 10, 100, 1000, 10000)]
public int ItemCount { get; set; }
}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

@EgorBo

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)
Example: #102805 (comment)
-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

It's correct as is (I already see 3 16-core VMs allocated for these requests😆) - it's just that currently there is no feedback that the jobs have started yet

@stephentoub

Copy link
Copy Markdown
Member

it's just that currently there is no feedback that the jobs have started yet

Ah! Ok. I'm used to the other bots that post a comment indicating that they've received the request. Thanks.

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
Job-UDSLNT : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Job-JPHOCC : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain1105.8 ns0.90 ns1.00
TestParallelToDictionaryPR18,586.0 ns47.85 ns81.20
TestSelectParallelToDictionaryMain18,611.2 ns37.32 ns1.00
TestSelectParallelToDictionaryPR18,805.7 ns72.94 ns1.02
TestWhereSelectParallelToDictionaryMain110,038.1 ns45.88 ns1.00
TestWhereSelectParallelToDictionaryPR110,348.0 ns60.22 ns1.03
TestParallelToDictionaryMain10390.3 ns3.63 ns1.00
TestParallelToDictionaryPR109,635.3 ns64.86 ns24.69
TestSelectParallelToDictionaryMain109,300.1 ns86.65 ns1.00
TestSelectParallelToDictionaryPR109,630.1 ns163.45 ns1.03
TestWhereSelectParallelToDictionaryMain1010,586.7 ns67.26 ns1.00
TestWhereSelectParallelToDictionaryPR1011,616.0 ns96.22 ns1.10
TestParallelToDictionaryMain1002,414.5 ns5.49 ns1.00
TestParallelToDictionaryPR10014,295.5 ns110.44 ns5.92
TestSelectParallelToDictionaryMain10013,759.9 ns110.77 ns1.00
TestSelectParallelToDictionaryPR10014,346.2 ns179.50 ns1.04
TestWhereSelectParallelToDictionaryMain10015,354.5 ns148.65 ns1.00
TestWhereSelectParallelToDictionaryPR10016,238.8 ns137.54 ns1.06
TestParallelToDictionaryMain100022,040.0 ns404.10 ns1.00
TestParallelToDictionaryPR100049,659.3 ns992.25 ns2.33
TestSelectParallelToDictionaryMain100050,769.5 ns992.20 ns1.00
TestSelectParallelToDictionaryPR100052,010.0 ns896.11 ns1.02
TestWhereSelectParallelToDictionaryMain100052,453.1 ns496.28 ns1.00
TestWhereSelectParallelToDictionaryPR100051,200.5 ns1,087.75 ns1.05
TestParallelToDictionaryMain10000317,249.3 ns4,007.57 ns1.00
TestParallelToDictionaryPR10000598,908.9 ns3,963.41 ns1.89
TestSelectParallelToDictionaryMain10000552,960.2 ns9,053.46 ns1.00
TestSelectParallelToDictionaryPR10000599,659.8 ns3,316.79 ns1.08
TestWhereSelectParallelToDictionaryMain10000560,577.1 ns5,482.61 ns1.00
TestWhereSelectParallelToDictionaryPR10000611,083.7 ns6,500.18 ns1.09

BDN_Artifacts.zip

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
Job-DMAJRO : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-CCUEBP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain168.87 ns0.774 ns1.00
TestParallelToDictionaryPR19,353.72 ns182.088 ns135.81
TestSelectParallelToDictionaryMain19,613.30 ns187.263 ns1.00
TestSelectParallelToDictionaryPR19,438.78 ns185.942 ns0.98
TestWhereSelectParallelToDictionaryMain110,173.87 ns202.386 ns1.00
TestWhereSelectParallelToDictionaryPR111,065.01 ns217.562 ns1.10
TestParallelToDictionaryMain10235.89 ns2.557 ns1.00
TestParallelToDictionaryPR109,453.04 ns182.520 ns40.04
TestSelectParallelToDictionaryMain109,254.72 ns157.309 ns1.00
TestSelectParallelToDictionaryPR1010,072.27 ns199.426 ns1.11
TestWhereSelectParallelToDictionaryMain1010,812.37 ns264.585 ns1.00
TestWhereSelectParallelToDictionaryPR1011,822.02 ns200.344 ns1.11
TestParallelToDictionaryMain1001,676.41 ns26.051 ns1.00
TestParallelToDictionaryPR10013,394.86 ns256.131 ns7.99
TestSelectParallelToDictionaryMain10012,813.12 ns255.738 ns1.00
TestSelectParallelToDictionaryPR10013,425.19 ns240.527 ns1.05
TestWhereSelectParallelToDictionaryMain10013,975.55 ns271.767 ns1.00
TestWhereSelectParallelToDictionaryPR10014,356.32 ns286.720 ns1.03
TestParallelToDictionaryMain100014,119.17 ns175.553 ns1.00
TestParallelToDictionaryPR100033,632.66 ns655.722 ns2.39
TestSelectParallelToDictionaryMain100031,916.77 ns507.908 ns1.00
TestSelectParallelToDictionaryPR100032,717.81 ns633.848 ns1.02
TestWhereSelectParallelToDictionaryMain100034,647.44 ns684.606 ns1.00
TestWhereSelectParallelToDictionaryPR100042,381.94 ns2,569.036 ns1.28
TestParallelToDictionaryMain10000216,167.31 ns341.834 ns1.00
TestParallelToDictionaryPR10000383,979.18 ns6,465.315 ns1.78
TestSelectParallelToDictionaryMain10000375,850.28 ns4,573.328 ns1.00
TestSelectParallelToDictionaryPR10000396,121.31 ns5,709.440 ns1.05
TestWhereSelectParallelToDictionaryMain10000376,878.77 ns7,402.242 ns1.00
TestWhereSelectParallelToDictionaryPR10000391,383.93 ns7,662.109 ns1.03

BDN_Artifacts.zip

@ericstj

Copy link
Copy Markdown
Member

It looks like @EgorBo's test results show some significant regressions. Am I reading that correctly @jozkee@stephentoub?

@stephentoub

Copy link
Copy Markdown
Member

Yes

@stephentoub

Copy link
Copy Markdown
Member

Closing per #96262 (comment). But thank you for the PR, regardless.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Linq.Parallelcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ParallelEnumerable.ToDictionary does not parallelize

6 participants

@lateapexearlyspeed@jozkee@stephentoub@EgorBo@EgorBot@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Make ToDictionary() selectors parallel. - #100590

Closed
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel
Closed

Make ToDictionary() selectors parallel.#100590
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel

Conversation

@lateapexearlyspeed

Copy link
Copy Markdown
Contributor

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 3, 2024
@jozkee

Copy link
Copy Markdown
Member

As stated in #96262 (comment), this will likely regress cases with a trivial key selector. @lateapexearlyspeed could you please provide a benchmark to see how bad it hits it so we can do an informed decision?

@jozkeejozkee added the needs-author-action An issue or pull request that requires more info or actions from the author. label May 20, 2024
@lateapexearlyspeed

Copy link
Copy Markdown
ContributorAuthor

@jozkee following is benchmark result of trivial key (and element) selector case. Toolchain in "runtime-main" is library before change and toolchain in "runtime" is library after change.

// * Summary *

BenchmarkDotNet=v0.13.1.1603-nightly, OS=Windows 10.0.22631
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
.NET SDK=8.0.202
[Host] : .NET 6.0.31 (6.0.3124.26714), X64 RyuJIT
Job-XVKCDM : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT
Job-ODFYHP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog IterationTime=250.0000 ms
MaxIterationCount=20 MinIterationCount=15 WarmupCount=1

MethodJobToolchainItemCountMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe142.00 ns9.363 ns10.782 ns35.46 ns32.76 ns62.01 ns1.000.000.0298--376 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe17,778.30 ns149.193 ns139.555 ns7,773.13 ns7,457.77 ns8,025.18 ns214.4327.420.6916--8,896 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10120.94 ns2.399 ns2.356 ns121.89 ns116.36 ns124.39 ns1.000.000.0765--960 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe108,034.68 ns190.599 ns219.495 ns8,038.56 ns7,658.90 ns8,423.41 ns66.692.110.7844--9,984 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe1001,054.74 ns94.978 ns109.377 ns1,025.83 ns905.00 ns1,335.60 ns1.000.000.60140.0073-7,576 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10010,700.76 ns295.269 ns328.191 ns10,768.11 ns10,152.59 ns11,369.07 ns10.201.001.5175--18,920 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10008,536.74 ns206.045 ns237.282 ns8,593.82 ns8,068.56 ns8,911.05 ns1.000.005.82940.6955-73,352 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe100045,359.53 ns1,780.828 ns2,050.804 ns44,628.87 ns42,440.57 ns50,316.83 ns5.310.228.32201.3587-104,118 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000175,304.48 ns5,273.794 ns6,073.309 ns174,695.64 ns166,454.45 ns186,023.27 ns1.000.00124.3351124.3351124.3351673,290 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000425,559.34 ns21,829.962 ns25,139.417 ns422,713.75 ns382,274.84 ns461,048.75 ns2.430.20131.2500131.2500123.4375848,901 B

[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}

@dotnet-policy-servicedotnet-policy-serviceBot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label May 29, 2024
@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -amd

usingSystem.Linq;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;BenchmarkRunner.Run<Tests>(args:args);publicclassTests{[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Select(i =>i).ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestWhereSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Where(i =>true).Select(i =>i).ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

@EgorBo

EgorBo commented May 29, 2024

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm]
it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args".
There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -intel -arm64

using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkRunner.Run<Tests>(args: args);
public class Tests
{
[Benchmark]
public void TestParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Select(i => i).ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestWhereSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Where(i => true).Select(i => i).ToDictionary(i => i, i => i);
}
[Params(1, 10, 100, 1000, 10000)]
public int ItemCount { get; set; }
}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

@EgorBo

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)
Example: #102805 (comment)
-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

It's correct as is (I already see 3 16-core VMs allocated for these requests😆) - it's just that currently there is no feedback that the jobs have started yet

@stephentoub

Copy link
Copy Markdown
Member

it's just that currently there is no feedback that the jobs have started yet

Ah! Ok. I'm used to the other bots that post a comment indicating that they've received the request. Thanks.

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
Job-UDSLNT : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Job-JPHOCC : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain1105.8 ns0.90 ns1.00
TestParallelToDictionaryPR18,586.0 ns47.85 ns81.20
TestSelectParallelToDictionaryMain18,611.2 ns37.32 ns1.00
TestSelectParallelToDictionaryPR18,805.7 ns72.94 ns1.02
TestWhereSelectParallelToDictionaryMain110,038.1 ns45.88 ns1.00
TestWhereSelectParallelToDictionaryPR110,348.0 ns60.22 ns1.03
TestParallelToDictionaryMain10390.3 ns3.63 ns1.00
TestParallelToDictionaryPR109,635.3 ns64.86 ns24.69
TestSelectParallelToDictionaryMain109,300.1 ns86.65 ns1.00
TestSelectParallelToDictionaryPR109,630.1 ns163.45 ns1.03
TestWhereSelectParallelToDictionaryMain1010,586.7 ns67.26 ns1.00
TestWhereSelectParallelToDictionaryPR1011,616.0 ns96.22 ns1.10
TestParallelToDictionaryMain1002,414.5 ns5.49 ns1.00
TestParallelToDictionaryPR10014,295.5 ns110.44 ns5.92
TestSelectParallelToDictionaryMain10013,759.9 ns110.77 ns1.00
TestSelectParallelToDictionaryPR10014,346.2 ns179.50 ns1.04
TestWhereSelectParallelToDictionaryMain10015,354.5 ns148.65 ns1.00
TestWhereSelectParallelToDictionaryPR10016,238.8 ns137.54 ns1.06
TestParallelToDictionaryMain100022,040.0 ns404.10 ns1.00
TestParallelToDictionaryPR100049,659.3 ns992.25 ns2.33
TestSelectParallelToDictionaryMain100050,769.5 ns992.20 ns1.00
TestSelectParallelToDictionaryPR100052,010.0 ns896.11 ns1.02
TestWhereSelectParallelToDictionaryMain100052,453.1 ns496.28 ns1.00
TestWhereSelectParallelToDictionaryPR100051,200.5 ns1,087.75 ns1.05
TestParallelToDictionaryMain10000317,249.3 ns4,007.57 ns1.00
TestParallelToDictionaryPR10000598,908.9 ns3,963.41 ns1.89
TestSelectParallelToDictionaryMain10000552,960.2 ns9,053.46 ns1.00
TestSelectParallelToDictionaryPR10000599,659.8 ns3,316.79 ns1.08
TestWhereSelectParallelToDictionaryMain10000560,577.1 ns5,482.61 ns1.00
TestWhereSelectParallelToDictionaryPR10000611,083.7 ns6,500.18 ns1.09

BDN_Artifacts.zip

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
Job-DMAJRO : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-CCUEBP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain168.87 ns0.774 ns1.00
TestParallelToDictionaryPR19,353.72 ns182.088 ns135.81
TestSelectParallelToDictionaryMain19,613.30 ns187.263 ns1.00
TestSelectParallelToDictionaryPR19,438.78 ns185.942 ns0.98
TestWhereSelectParallelToDictionaryMain110,173.87 ns202.386 ns1.00
TestWhereSelectParallelToDictionaryPR111,065.01 ns217.562 ns1.10
TestParallelToDictionaryMain10235.89 ns2.557 ns1.00
TestParallelToDictionaryPR109,453.04 ns182.520 ns40.04
TestSelectParallelToDictionaryMain109,254.72 ns157.309 ns1.00
TestSelectParallelToDictionaryPR1010,072.27 ns199.426 ns1.11
TestWhereSelectParallelToDictionaryMain1010,812.37 ns264.585 ns1.00
TestWhereSelectParallelToDictionaryPR1011,822.02 ns200.344 ns1.11
TestParallelToDictionaryMain1001,676.41 ns26.051 ns1.00
TestParallelToDictionaryPR10013,394.86 ns256.131 ns7.99
TestSelectParallelToDictionaryMain10012,813.12 ns255.738 ns1.00
TestSelectParallelToDictionaryPR10013,425.19 ns240.527 ns1.05
TestWhereSelectParallelToDictionaryMain10013,975.55 ns271.767 ns1.00
TestWhereSelectParallelToDictionaryPR10014,356.32 ns286.720 ns1.03
TestParallelToDictionaryMain100014,119.17 ns175.553 ns1.00
TestParallelToDictionaryPR100033,632.66 ns655.722 ns2.39
TestSelectParallelToDictionaryMain100031,916.77 ns507.908 ns1.00
TestSelectParallelToDictionaryPR100032,717.81 ns633.848 ns1.02
TestWhereSelectParallelToDictionaryMain100034,647.44 ns684.606 ns1.00
TestWhereSelectParallelToDictionaryPR100042,381.94 ns2,569.036 ns1.28
TestParallelToDictionaryMain10000216,167.31 ns341.834 ns1.00
TestParallelToDictionaryPR10000383,979.18 ns6,465.315 ns1.78
TestSelectParallelToDictionaryMain10000375,850.28 ns4,573.328 ns1.00
TestSelectParallelToDictionaryPR10000396,121.31 ns5,709.440 ns1.05
TestWhereSelectParallelToDictionaryMain10000376,878.77 ns7,402.242 ns1.00
TestWhereSelectParallelToDictionaryPR10000391,383.93 ns7,662.109 ns1.03

BDN_Artifacts.zip

@ericstj

Copy link
Copy Markdown
Member

It looks like @EgorBo's test results show some significant regressions. Am I reading that correctly @jozkee@stephentoub?

@stephentoub

Copy link
Copy Markdown
Member

Yes

@stephentoub

Copy link
Copy Markdown
Member

Closing per #96262 (comment). But thank you for the PR, regardless.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Linq.Parallelcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ParallelEnumerable.ToDictionary does not parallelize

6 participants

@lateapexearlyspeed@jozkee@stephentoub@EgorBo@EgorBot@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Make ToDictionary() selectors parallel. - #100590

Closed
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel
Closed

Make ToDictionary() selectors parallel.#100590
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel

Conversation

@lateapexearlyspeed

Copy link
Copy Markdown
Contributor

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 3, 2024
@jozkee

Copy link
Copy Markdown
Member

As stated in #96262 (comment), this will likely regress cases with a trivial key selector. @lateapexearlyspeed could you please provide a benchmark to see how bad it hits it so we can do an informed decision?

@jozkeejozkee added the needs-author-action An issue or pull request that requires more info or actions from the author. label May 20, 2024
@lateapexearlyspeed

Copy link
Copy Markdown
ContributorAuthor

@jozkee following is benchmark result of trivial key (and element) selector case. Toolchain in "runtime-main" is library before change and toolchain in "runtime" is library after change.

// * Summary *

BenchmarkDotNet=v0.13.1.1603-nightly, OS=Windows 10.0.22631
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
.NET SDK=8.0.202
[Host] : .NET 6.0.31 (6.0.3124.26714), X64 RyuJIT
Job-XVKCDM : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT
Job-ODFYHP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog IterationTime=250.0000 ms
MaxIterationCount=20 MinIterationCount=15 WarmupCount=1

MethodJobToolchainItemCountMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe142.00 ns9.363 ns10.782 ns35.46 ns32.76 ns62.01 ns1.000.000.0298--376 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe17,778.30 ns149.193 ns139.555 ns7,773.13 ns7,457.77 ns8,025.18 ns214.4327.420.6916--8,896 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10120.94 ns2.399 ns2.356 ns121.89 ns116.36 ns124.39 ns1.000.000.0765--960 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe108,034.68 ns190.599 ns219.495 ns8,038.56 ns7,658.90 ns8,423.41 ns66.692.110.7844--9,984 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe1001,054.74 ns94.978 ns109.377 ns1,025.83 ns905.00 ns1,335.60 ns1.000.000.60140.0073-7,576 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10010,700.76 ns295.269 ns328.191 ns10,768.11 ns10,152.59 ns11,369.07 ns10.201.001.5175--18,920 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10008,536.74 ns206.045 ns237.282 ns8,593.82 ns8,068.56 ns8,911.05 ns1.000.005.82940.6955-73,352 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe100045,359.53 ns1,780.828 ns2,050.804 ns44,628.87 ns42,440.57 ns50,316.83 ns5.310.228.32201.3587-104,118 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000175,304.48 ns5,273.794 ns6,073.309 ns174,695.64 ns166,454.45 ns186,023.27 ns1.000.00124.3351124.3351124.3351673,290 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000425,559.34 ns21,829.962 ns25,139.417 ns422,713.75 ns382,274.84 ns461,048.75 ns2.430.20131.2500131.2500123.4375848,901 B

[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}

@dotnet-policy-servicedotnet-policy-serviceBot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label May 29, 2024
@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -amd

usingSystem.Linq;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;BenchmarkRunner.Run<Tests>(args:args);publicclassTests{[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Select(i =>i).ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestWhereSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Where(i =>true).Select(i =>i).ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

@EgorBo

EgorBo commented May 29, 2024

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm]
it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args".
There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -intel -arm64

using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkRunner.Run<Tests>(args: args);
public class Tests
{
[Benchmark]
public void TestParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Select(i => i).ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestWhereSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Where(i => true).Select(i => i).ToDictionary(i => i, i => i);
}
[Params(1, 10, 100, 1000, 10000)]
public int ItemCount { get; set; }
}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

@EgorBo

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)
Example: #102805 (comment)
-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

It's correct as is (I already see 3 16-core VMs allocated for these requests😆) - it's just that currently there is no feedback that the jobs have started yet

@stephentoub

Copy link
Copy Markdown
Member

it's just that currently there is no feedback that the jobs have started yet

Ah! Ok. I'm used to the other bots that post a comment indicating that they've received the request. Thanks.

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
Job-UDSLNT : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Job-JPHOCC : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain1105.8 ns0.90 ns1.00
TestParallelToDictionaryPR18,586.0 ns47.85 ns81.20
TestSelectParallelToDictionaryMain18,611.2 ns37.32 ns1.00
TestSelectParallelToDictionaryPR18,805.7 ns72.94 ns1.02
TestWhereSelectParallelToDictionaryMain110,038.1 ns45.88 ns1.00
TestWhereSelectParallelToDictionaryPR110,348.0 ns60.22 ns1.03
TestParallelToDictionaryMain10390.3 ns3.63 ns1.00
TestParallelToDictionaryPR109,635.3 ns64.86 ns24.69
TestSelectParallelToDictionaryMain109,300.1 ns86.65 ns1.00
TestSelectParallelToDictionaryPR109,630.1 ns163.45 ns1.03
TestWhereSelectParallelToDictionaryMain1010,586.7 ns67.26 ns1.00
TestWhereSelectParallelToDictionaryPR1011,616.0 ns96.22 ns1.10
TestParallelToDictionaryMain1002,414.5 ns5.49 ns1.00
TestParallelToDictionaryPR10014,295.5 ns110.44 ns5.92
TestSelectParallelToDictionaryMain10013,759.9 ns110.77 ns1.00
TestSelectParallelToDictionaryPR10014,346.2 ns179.50 ns1.04
TestWhereSelectParallelToDictionaryMain10015,354.5 ns148.65 ns1.00
TestWhereSelectParallelToDictionaryPR10016,238.8 ns137.54 ns1.06
TestParallelToDictionaryMain100022,040.0 ns404.10 ns1.00
TestParallelToDictionaryPR100049,659.3 ns992.25 ns2.33
TestSelectParallelToDictionaryMain100050,769.5 ns992.20 ns1.00
TestSelectParallelToDictionaryPR100052,010.0 ns896.11 ns1.02
TestWhereSelectParallelToDictionaryMain100052,453.1 ns496.28 ns1.00
TestWhereSelectParallelToDictionaryPR100051,200.5 ns1,087.75 ns1.05
TestParallelToDictionaryMain10000317,249.3 ns4,007.57 ns1.00
TestParallelToDictionaryPR10000598,908.9 ns3,963.41 ns1.89
TestSelectParallelToDictionaryMain10000552,960.2 ns9,053.46 ns1.00
TestSelectParallelToDictionaryPR10000599,659.8 ns3,316.79 ns1.08
TestWhereSelectParallelToDictionaryMain10000560,577.1 ns5,482.61 ns1.00
TestWhereSelectParallelToDictionaryPR10000611,083.7 ns6,500.18 ns1.09

BDN_Artifacts.zip

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
Job-DMAJRO : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-CCUEBP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain168.87 ns0.774 ns1.00
TestParallelToDictionaryPR19,353.72 ns182.088 ns135.81
TestSelectParallelToDictionaryMain19,613.30 ns187.263 ns1.00
TestSelectParallelToDictionaryPR19,438.78 ns185.942 ns0.98
TestWhereSelectParallelToDictionaryMain110,173.87 ns202.386 ns1.00
TestWhereSelectParallelToDictionaryPR111,065.01 ns217.562 ns1.10
TestParallelToDictionaryMain10235.89 ns2.557 ns1.00
TestParallelToDictionaryPR109,453.04 ns182.520 ns40.04
TestSelectParallelToDictionaryMain109,254.72 ns157.309 ns1.00
TestSelectParallelToDictionaryPR1010,072.27 ns199.426 ns1.11
TestWhereSelectParallelToDictionaryMain1010,812.37 ns264.585 ns1.00
TestWhereSelectParallelToDictionaryPR1011,822.02 ns200.344 ns1.11
TestParallelToDictionaryMain1001,676.41 ns26.051 ns1.00
TestParallelToDictionaryPR10013,394.86 ns256.131 ns7.99
TestSelectParallelToDictionaryMain10012,813.12 ns255.738 ns1.00
TestSelectParallelToDictionaryPR10013,425.19 ns240.527 ns1.05
TestWhereSelectParallelToDictionaryMain10013,975.55 ns271.767 ns1.00
TestWhereSelectParallelToDictionaryPR10014,356.32 ns286.720 ns1.03
TestParallelToDictionaryMain100014,119.17 ns175.553 ns1.00
TestParallelToDictionaryPR100033,632.66 ns655.722 ns2.39
TestSelectParallelToDictionaryMain100031,916.77 ns507.908 ns1.00
TestSelectParallelToDictionaryPR100032,717.81 ns633.848 ns1.02
TestWhereSelectParallelToDictionaryMain100034,647.44 ns684.606 ns1.00
TestWhereSelectParallelToDictionaryPR100042,381.94 ns2,569.036 ns1.28
TestParallelToDictionaryMain10000216,167.31 ns341.834 ns1.00
TestParallelToDictionaryPR10000383,979.18 ns6,465.315 ns1.78
TestSelectParallelToDictionaryMain10000375,850.28 ns4,573.328 ns1.00
TestSelectParallelToDictionaryPR10000396,121.31 ns5,709.440 ns1.05
TestWhereSelectParallelToDictionaryMain10000376,878.77 ns7,402.242 ns1.00
TestWhereSelectParallelToDictionaryPR10000391,383.93 ns7,662.109 ns1.03

BDN_Artifacts.zip

@ericstj

Copy link
Copy Markdown
Member

It looks like @EgorBo's test results show some significant regressions. Am I reading that correctly @jozkee@stephentoub?

@stephentoub

Copy link
Copy Markdown
Member

Yes

@stephentoub

Copy link
Copy Markdown
Member

Closing per #96262 (comment). But thank you for the PR, regardless.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Linq.Parallelcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ParallelEnumerable.ToDictionary does not parallelize

6 participants

@lateapexearlyspeed@jozkee@stephentoub@EgorBo@EgorBot@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Make ToDictionary() selectors parallel. - #100590

Closed
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel
Closed

Make ToDictionary() selectors parallel.#100590
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel

Conversation

@lateapexearlyspeed

Copy link
Copy Markdown
Contributor

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 3, 2024
@jozkee

Copy link
Copy Markdown
Member

As stated in #96262 (comment), this will likely regress cases with a trivial key selector. @lateapexearlyspeed could you please provide a benchmark to see how bad it hits it so we can do an informed decision?

@jozkeejozkee added the needs-author-action An issue or pull request that requires more info or actions from the author. label May 20, 2024
@lateapexearlyspeed

Copy link
Copy Markdown
ContributorAuthor

@jozkee following is benchmark result of trivial key (and element) selector case. Toolchain in "runtime-main" is library before change and toolchain in "runtime" is library after change.

// * Summary *

BenchmarkDotNet=v0.13.1.1603-nightly, OS=Windows 10.0.22631
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
.NET SDK=8.0.202
[Host] : .NET 6.0.31 (6.0.3124.26714), X64 RyuJIT
Job-XVKCDM : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT
Job-ODFYHP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog IterationTime=250.0000 ms
MaxIterationCount=20 MinIterationCount=15 WarmupCount=1

MethodJobToolchainItemCountMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe142.00 ns9.363 ns10.782 ns35.46 ns32.76 ns62.01 ns1.000.000.0298--376 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe17,778.30 ns149.193 ns139.555 ns7,773.13 ns7,457.77 ns8,025.18 ns214.4327.420.6916--8,896 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10120.94 ns2.399 ns2.356 ns121.89 ns116.36 ns124.39 ns1.000.000.0765--960 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe108,034.68 ns190.599 ns219.495 ns8,038.56 ns7,658.90 ns8,423.41 ns66.692.110.7844--9,984 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe1001,054.74 ns94.978 ns109.377 ns1,025.83 ns905.00 ns1,335.60 ns1.000.000.60140.0073-7,576 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10010,700.76 ns295.269 ns328.191 ns10,768.11 ns10,152.59 ns11,369.07 ns10.201.001.5175--18,920 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10008,536.74 ns206.045 ns237.282 ns8,593.82 ns8,068.56 ns8,911.05 ns1.000.005.82940.6955-73,352 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe100045,359.53 ns1,780.828 ns2,050.804 ns44,628.87 ns42,440.57 ns50,316.83 ns5.310.228.32201.3587-104,118 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000175,304.48 ns5,273.794 ns6,073.309 ns174,695.64 ns166,454.45 ns186,023.27 ns1.000.00124.3351124.3351124.3351673,290 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000425,559.34 ns21,829.962 ns25,139.417 ns422,713.75 ns382,274.84 ns461,048.75 ns2.430.20131.2500131.2500123.4375848,901 B

[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}

@dotnet-policy-servicedotnet-policy-serviceBot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label May 29, 2024
@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -amd

usingSystem.Linq;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;BenchmarkRunner.Run<Tests>(args:args);publicclassTests{[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Select(i =>i).ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestWhereSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Where(i =>true).Select(i =>i).ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

@EgorBo

EgorBo commented May 29, 2024

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm]
it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args".
There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -intel -arm64

using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkRunner.Run<Tests>(args: args);
public class Tests
{
[Benchmark]
public void TestParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Select(i => i).ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestWhereSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Where(i => true).Select(i => i).ToDictionary(i => i, i => i);
}
[Params(1, 10, 100, 1000, 10000)]
public int ItemCount { get; set; }
}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

@EgorBo

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)
Example: #102805 (comment)
-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

It's correct as is (I already see 3 16-core VMs allocated for these requests😆) - it's just that currently there is no feedback that the jobs have started yet

@stephentoub

Copy link
Copy Markdown
Member

it's just that currently there is no feedback that the jobs have started yet

Ah! Ok. I'm used to the other bots that post a comment indicating that they've received the request. Thanks.

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
Job-UDSLNT : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Job-JPHOCC : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain1105.8 ns0.90 ns1.00
TestParallelToDictionaryPR18,586.0 ns47.85 ns81.20
TestSelectParallelToDictionaryMain18,611.2 ns37.32 ns1.00
TestSelectParallelToDictionaryPR18,805.7 ns72.94 ns1.02
TestWhereSelectParallelToDictionaryMain110,038.1 ns45.88 ns1.00
TestWhereSelectParallelToDictionaryPR110,348.0 ns60.22 ns1.03
TestParallelToDictionaryMain10390.3 ns3.63 ns1.00
TestParallelToDictionaryPR109,635.3 ns64.86 ns24.69
TestSelectParallelToDictionaryMain109,300.1 ns86.65 ns1.00
TestSelectParallelToDictionaryPR109,630.1 ns163.45 ns1.03
TestWhereSelectParallelToDictionaryMain1010,586.7 ns67.26 ns1.00
TestWhereSelectParallelToDictionaryPR1011,616.0 ns96.22 ns1.10
TestParallelToDictionaryMain1002,414.5 ns5.49 ns1.00
TestParallelToDictionaryPR10014,295.5 ns110.44 ns5.92
TestSelectParallelToDictionaryMain10013,759.9 ns110.77 ns1.00
TestSelectParallelToDictionaryPR10014,346.2 ns179.50 ns1.04
TestWhereSelectParallelToDictionaryMain10015,354.5 ns148.65 ns1.00
TestWhereSelectParallelToDictionaryPR10016,238.8 ns137.54 ns1.06
TestParallelToDictionaryMain100022,040.0 ns404.10 ns1.00
TestParallelToDictionaryPR100049,659.3 ns992.25 ns2.33
TestSelectParallelToDictionaryMain100050,769.5 ns992.20 ns1.00
TestSelectParallelToDictionaryPR100052,010.0 ns896.11 ns1.02
TestWhereSelectParallelToDictionaryMain100052,453.1 ns496.28 ns1.00
TestWhereSelectParallelToDictionaryPR100051,200.5 ns1,087.75 ns1.05
TestParallelToDictionaryMain10000317,249.3 ns4,007.57 ns1.00
TestParallelToDictionaryPR10000598,908.9 ns3,963.41 ns1.89
TestSelectParallelToDictionaryMain10000552,960.2 ns9,053.46 ns1.00
TestSelectParallelToDictionaryPR10000599,659.8 ns3,316.79 ns1.08
TestWhereSelectParallelToDictionaryMain10000560,577.1 ns5,482.61 ns1.00
TestWhereSelectParallelToDictionaryPR10000611,083.7 ns6,500.18 ns1.09

BDN_Artifacts.zip

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
Job-DMAJRO : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-CCUEBP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain168.87 ns0.774 ns1.00
TestParallelToDictionaryPR19,353.72 ns182.088 ns135.81
TestSelectParallelToDictionaryMain19,613.30 ns187.263 ns1.00
TestSelectParallelToDictionaryPR19,438.78 ns185.942 ns0.98
TestWhereSelectParallelToDictionaryMain110,173.87 ns202.386 ns1.00
TestWhereSelectParallelToDictionaryPR111,065.01 ns217.562 ns1.10
TestParallelToDictionaryMain10235.89 ns2.557 ns1.00
TestParallelToDictionaryPR109,453.04 ns182.520 ns40.04
TestSelectParallelToDictionaryMain109,254.72 ns157.309 ns1.00
TestSelectParallelToDictionaryPR1010,072.27 ns199.426 ns1.11
TestWhereSelectParallelToDictionaryMain1010,812.37 ns264.585 ns1.00
TestWhereSelectParallelToDictionaryPR1011,822.02 ns200.344 ns1.11
TestParallelToDictionaryMain1001,676.41 ns26.051 ns1.00
TestParallelToDictionaryPR10013,394.86 ns256.131 ns7.99
TestSelectParallelToDictionaryMain10012,813.12 ns255.738 ns1.00
TestSelectParallelToDictionaryPR10013,425.19 ns240.527 ns1.05
TestWhereSelectParallelToDictionaryMain10013,975.55 ns271.767 ns1.00
TestWhereSelectParallelToDictionaryPR10014,356.32 ns286.720 ns1.03
TestParallelToDictionaryMain100014,119.17 ns175.553 ns1.00
TestParallelToDictionaryPR100033,632.66 ns655.722 ns2.39
TestSelectParallelToDictionaryMain100031,916.77 ns507.908 ns1.00
TestSelectParallelToDictionaryPR100032,717.81 ns633.848 ns1.02
TestWhereSelectParallelToDictionaryMain100034,647.44 ns684.606 ns1.00
TestWhereSelectParallelToDictionaryPR100042,381.94 ns2,569.036 ns1.28
TestParallelToDictionaryMain10000216,167.31 ns341.834 ns1.00
TestParallelToDictionaryPR10000383,979.18 ns6,465.315 ns1.78
TestSelectParallelToDictionaryMain10000375,850.28 ns4,573.328 ns1.00
TestSelectParallelToDictionaryPR10000396,121.31 ns5,709.440 ns1.05
TestWhereSelectParallelToDictionaryMain10000376,878.77 ns7,402.242 ns1.00
TestWhereSelectParallelToDictionaryPR10000391,383.93 ns7,662.109 ns1.03

BDN_Artifacts.zip

@ericstj

Copy link
Copy Markdown
Member

It looks like @EgorBo's test results show some significant regressions. Am I reading that correctly @jozkee@stephentoub?

@stephentoub

Copy link
Copy Markdown
Member

Yes

@stephentoub

Copy link
Copy Markdown
Member

Closing per #96262 (comment). But thank you for the PR, regardless.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Linq.Parallelcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ParallelEnumerable.ToDictionary does not parallelize

6 participants

@lateapexearlyspeed@jozkee@stephentoub@EgorBo@EgorBot@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Make ToDictionary() selectors parallel. - #100590

Closed
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel
Closed

Make ToDictionary() selectors parallel.#100590
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel

Conversation

@lateapexearlyspeed

Copy link
Copy Markdown
Contributor

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 3, 2024
@jozkee

Copy link
Copy Markdown
Member

As stated in #96262 (comment), this will likely regress cases with a trivial key selector. @lateapexearlyspeed could you please provide a benchmark to see how bad it hits it so we can do an informed decision?

@jozkeejozkee added the needs-author-action An issue or pull request that requires more info or actions from the author. label May 20, 2024
@lateapexearlyspeed

Copy link
Copy Markdown
ContributorAuthor

@jozkee following is benchmark result of trivial key (and element) selector case. Toolchain in "runtime-main" is library before change and toolchain in "runtime" is library after change.

// * Summary *

BenchmarkDotNet=v0.13.1.1603-nightly, OS=Windows 10.0.22631
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
.NET SDK=8.0.202
[Host] : .NET 6.0.31 (6.0.3124.26714), X64 RyuJIT
Job-XVKCDM : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT
Job-ODFYHP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog IterationTime=250.0000 ms
MaxIterationCount=20 MinIterationCount=15 WarmupCount=1

MethodJobToolchainItemCountMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe142.00 ns9.363 ns10.782 ns35.46 ns32.76 ns62.01 ns1.000.000.0298--376 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe17,778.30 ns149.193 ns139.555 ns7,773.13 ns7,457.77 ns8,025.18 ns214.4327.420.6916--8,896 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10120.94 ns2.399 ns2.356 ns121.89 ns116.36 ns124.39 ns1.000.000.0765--960 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe108,034.68 ns190.599 ns219.495 ns8,038.56 ns7,658.90 ns8,423.41 ns66.692.110.7844--9,984 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe1001,054.74 ns94.978 ns109.377 ns1,025.83 ns905.00 ns1,335.60 ns1.000.000.60140.0073-7,576 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10010,700.76 ns295.269 ns328.191 ns10,768.11 ns10,152.59 ns11,369.07 ns10.201.001.5175--18,920 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10008,536.74 ns206.045 ns237.282 ns8,593.82 ns8,068.56 ns8,911.05 ns1.000.005.82940.6955-73,352 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe100045,359.53 ns1,780.828 ns2,050.804 ns44,628.87 ns42,440.57 ns50,316.83 ns5.310.228.32201.3587-104,118 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000175,304.48 ns5,273.794 ns6,073.309 ns174,695.64 ns166,454.45 ns186,023.27 ns1.000.00124.3351124.3351124.3351673,290 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000425,559.34 ns21,829.962 ns25,139.417 ns422,713.75 ns382,274.84 ns461,048.75 ns2.430.20131.2500131.2500123.4375848,901 B

[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}

@dotnet-policy-servicedotnet-policy-serviceBot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label May 29, 2024
@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -amd

usingSystem.Linq;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;BenchmarkRunner.Run<Tests>(args:args);publicclassTests{[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Select(i =>i).ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestWhereSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Where(i =>true).Select(i =>i).ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

@EgorBo

EgorBo commented May 29, 2024

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm]
it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args".
There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -intel -arm64

using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkRunner.Run<Tests>(args: args);
public class Tests
{
[Benchmark]
public void TestParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Select(i => i).ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestWhereSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Where(i => true).Select(i => i).ToDictionary(i => i, i => i);
}
[Params(1, 10, 100, 1000, 10000)]
public int ItemCount { get; set; }
}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

@EgorBo

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)
Example: #102805 (comment)
-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

It's correct as is (I already see 3 16-core VMs allocated for these requests😆) - it's just that currently there is no feedback that the jobs have started yet

@stephentoub

Copy link
Copy Markdown
Member

it's just that currently there is no feedback that the jobs have started yet

Ah! Ok. I'm used to the other bots that post a comment indicating that they've received the request. Thanks.

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
Job-UDSLNT : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Job-JPHOCC : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain1105.8 ns0.90 ns1.00
TestParallelToDictionaryPR18,586.0 ns47.85 ns81.20
TestSelectParallelToDictionaryMain18,611.2 ns37.32 ns1.00
TestSelectParallelToDictionaryPR18,805.7 ns72.94 ns1.02
TestWhereSelectParallelToDictionaryMain110,038.1 ns45.88 ns1.00
TestWhereSelectParallelToDictionaryPR110,348.0 ns60.22 ns1.03
TestParallelToDictionaryMain10390.3 ns3.63 ns1.00
TestParallelToDictionaryPR109,635.3 ns64.86 ns24.69
TestSelectParallelToDictionaryMain109,300.1 ns86.65 ns1.00
TestSelectParallelToDictionaryPR109,630.1 ns163.45 ns1.03
TestWhereSelectParallelToDictionaryMain1010,586.7 ns67.26 ns1.00
TestWhereSelectParallelToDictionaryPR1011,616.0 ns96.22 ns1.10
TestParallelToDictionaryMain1002,414.5 ns5.49 ns1.00
TestParallelToDictionaryPR10014,295.5 ns110.44 ns5.92
TestSelectParallelToDictionaryMain10013,759.9 ns110.77 ns1.00
TestSelectParallelToDictionaryPR10014,346.2 ns179.50 ns1.04
TestWhereSelectParallelToDictionaryMain10015,354.5 ns148.65 ns1.00
TestWhereSelectParallelToDictionaryPR10016,238.8 ns137.54 ns1.06
TestParallelToDictionaryMain100022,040.0 ns404.10 ns1.00
TestParallelToDictionaryPR100049,659.3 ns992.25 ns2.33
TestSelectParallelToDictionaryMain100050,769.5 ns992.20 ns1.00
TestSelectParallelToDictionaryPR100052,010.0 ns896.11 ns1.02
TestWhereSelectParallelToDictionaryMain100052,453.1 ns496.28 ns1.00
TestWhereSelectParallelToDictionaryPR100051,200.5 ns1,087.75 ns1.05
TestParallelToDictionaryMain10000317,249.3 ns4,007.57 ns1.00
TestParallelToDictionaryPR10000598,908.9 ns3,963.41 ns1.89
TestSelectParallelToDictionaryMain10000552,960.2 ns9,053.46 ns1.00
TestSelectParallelToDictionaryPR10000599,659.8 ns3,316.79 ns1.08
TestWhereSelectParallelToDictionaryMain10000560,577.1 ns5,482.61 ns1.00
TestWhereSelectParallelToDictionaryPR10000611,083.7 ns6,500.18 ns1.09

BDN_Artifacts.zip

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
Job-DMAJRO : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-CCUEBP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain168.87 ns0.774 ns1.00
TestParallelToDictionaryPR19,353.72 ns182.088 ns135.81
TestSelectParallelToDictionaryMain19,613.30 ns187.263 ns1.00
TestSelectParallelToDictionaryPR19,438.78 ns185.942 ns0.98
TestWhereSelectParallelToDictionaryMain110,173.87 ns202.386 ns1.00
TestWhereSelectParallelToDictionaryPR111,065.01 ns217.562 ns1.10
TestParallelToDictionaryMain10235.89 ns2.557 ns1.00
TestParallelToDictionaryPR109,453.04 ns182.520 ns40.04
TestSelectParallelToDictionaryMain109,254.72 ns157.309 ns1.00
TestSelectParallelToDictionaryPR1010,072.27 ns199.426 ns1.11
TestWhereSelectParallelToDictionaryMain1010,812.37 ns264.585 ns1.00
TestWhereSelectParallelToDictionaryPR1011,822.02 ns200.344 ns1.11
TestParallelToDictionaryMain1001,676.41 ns26.051 ns1.00
TestParallelToDictionaryPR10013,394.86 ns256.131 ns7.99
TestSelectParallelToDictionaryMain10012,813.12 ns255.738 ns1.00
TestSelectParallelToDictionaryPR10013,425.19 ns240.527 ns1.05
TestWhereSelectParallelToDictionaryMain10013,975.55 ns271.767 ns1.00
TestWhereSelectParallelToDictionaryPR10014,356.32 ns286.720 ns1.03
TestParallelToDictionaryMain100014,119.17 ns175.553 ns1.00
TestParallelToDictionaryPR100033,632.66 ns655.722 ns2.39
TestSelectParallelToDictionaryMain100031,916.77 ns507.908 ns1.00
TestSelectParallelToDictionaryPR100032,717.81 ns633.848 ns1.02
TestWhereSelectParallelToDictionaryMain100034,647.44 ns684.606 ns1.00
TestWhereSelectParallelToDictionaryPR100042,381.94 ns2,569.036 ns1.28
TestParallelToDictionaryMain10000216,167.31 ns341.834 ns1.00
TestParallelToDictionaryPR10000383,979.18 ns6,465.315 ns1.78
TestSelectParallelToDictionaryMain10000375,850.28 ns4,573.328 ns1.00
TestSelectParallelToDictionaryPR10000396,121.31 ns5,709.440 ns1.05
TestWhereSelectParallelToDictionaryMain10000376,878.77 ns7,402.242 ns1.00
TestWhereSelectParallelToDictionaryPR10000391,383.93 ns7,662.109 ns1.03

BDN_Artifacts.zip

@ericstj

Copy link
Copy Markdown
Member

It looks like @EgorBo's test results show some significant regressions. Am I reading that correctly @jozkee@stephentoub?

@stephentoub

Copy link
Copy Markdown
Member

Yes

@stephentoub

Copy link
Copy Markdown
Member

Closing per #96262 (comment). But thank you for the PR, regardless.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Linq.Parallelcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ParallelEnumerable.ToDictionary does not parallelize

6 participants

@lateapexearlyspeed@jozkee@stephentoub@EgorBo@EgorBot@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Make ToDictionary() selectors parallel. - #100590

Closed
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel
Closed

Make ToDictionary() selectors parallel.#100590
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel

Conversation

@lateapexearlyspeed

Copy link
Copy Markdown
Contributor

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 3, 2024
@jozkee

Copy link
Copy Markdown
Member

As stated in #96262 (comment), this will likely regress cases with a trivial key selector. @lateapexearlyspeed could you please provide a benchmark to see how bad it hits it so we can do an informed decision?

@jozkeejozkee added the needs-author-action An issue or pull request that requires more info or actions from the author. label May 20, 2024
@lateapexearlyspeed

Copy link
Copy Markdown
ContributorAuthor

@jozkee following is benchmark result of trivial key (and element) selector case. Toolchain in "runtime-main" is library before change and toolchain in "runtime" is library after change.

// * Summary *

BenchmarkDotNet=v0.13.1.1603-nightly, OS=Windows 10.0.22631
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
.NET SDK=8.0.202
[Host] : .NET 6.0.31 (6.0.3124.26714), X64 RyuJIT
Job-XVKCDM : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT
Job-ODFYHP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog IterationTime=250.0000 ms
MaxIterationCount=20 MinIterationCount=15 WarmupCount=1

MethodJobToolchainItemCountMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe142.00 ns9.363 ns10.782 ns35.46 ns32.76 ns62.01 ns1.000.000.0298--376 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe17,778.30 ns149.193 ns139.555 ns7,773.13 ns7,457.77 ns8,025.18 ns214.4327.420.6916--8,896 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10120.94 ns2.399 ns2.356 ns121.89 ns116.36 ns124.39 ns1.000.000.0765--960 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe108,034.68 ns190.599 ns219.495 ns8,038.56 ns7,658.90 ns8,423.41 ns66.692.110.7844--9,984 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe1001,054.74 ns94.978 ns109.377 ns1,025.83 ns905.00 ns1,335.60 ns1.000.000.60140.0073-7,576 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10010,700.76 ns295.269 ns328.191 ns10,768.11 ns10,152.59 ns11,369.07 ns10.201.001.5175--18,920 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10008,536.74 ns206.045 ns237.282 ns8,593.82 ns8,068.56 ns8,911.05 ns1.000.005.82940.6955-73,352 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe100045,359.53 ns1,780.828 ns2,050.804 ns44,628.87 ns42,440.57 ns50,316.83 ns5.310.228.32201.3587-104,118 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000175,304.48 ns5,273.794 ns6,073.309 ns174,695.64 ns166,454.45 ns186,023.27 ns1.000.00124.3351124.3351124.3351673,290 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000425,559.34 ns21,829.962 ns25,139.417 ns422,713.75 ns382,274.84 ns461,048.75 ns2.430.20131.2500131.2500123.4375848,901 B

[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}

@dotnet-policy-servicedotnet-policy-serviceBot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label May 29, 2024
@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -amd

usingSystem.Linq;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;BenchmarkRunner.Run<Tests>(args:args);publicclassTests{[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Select(i =>i).ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestWhereSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Where(i =>true).Select(i =>i).ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

@EgorBo

EgorBo commented May 29, 2024

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm]
it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args".
There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -intel -arm64

using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkRunner.Run<Tests>(args: args);
public class Tests
{
[Benchmark]
public void TestParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Select(i => i).ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestWhereSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Where(i => true).Select(i => i).ToDictionary(i => i, i => i);
}
[Params(1, 10, 100, 1000, 10000)]
public int ItemCount { get; set; }
}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

@EgorBo

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)
Example: #102805 (comment)
-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

It's correct as is (I already see 3 16-core VMs allocated for these requests😆) - it's just that currently there is no feedback that the jobs have started yet

@stephentoub

Copy link
Copy Markdown
Member

it's just that currently there is no feedback that the jobs have started yet

Ah! Ok. I'm used to the other bots that post a comment indicating that they've received the request. Thanks.

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
Job-UDSLNT : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Job-JPHOCC : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain1105.8 ns0.90 ns1.00
TestParallelToDictionaryPR18,586.0 ns47.85 ns81.20
TestSelectParallelToDictionaryMain18,611.2 ns37.32 ns1.00
TestSelectParallelToDictionaryPR18,805.7 ns72.94 ns1.02
TestWhereSelectParallelToDictionaryMain110,038.1 ns45.88 ns1.00
TestWhereSelectParallelToDictionaryPR110,348.0 ns60.22 ns1.03
TestParallelToDictionaryMain10390.3 ns3.63 ns1.00
TestParallelToDictionaryPR109,635.3 ns64.86 ns24.69
TestSelectParallelToDictionaryMain109,300.1 ns86.65 ns1.00
TestSelectParallelToDictionaryPR109,630.1 ns163.45 ns1.03
TestWhereSelectParallelToDictionaryMain1010,586.7 ns67.26 ns1.00
TestWhereSelectParallelToDictionaryPR1011,616.0 ns96.22 ns1.10
TestParallelToDictionaryMain1002,414.5 ns5.49 ns1.00
TestParallelToDictionaryPR10014,295.5 ns110.44 ns5.92
TestSelectParallelToDictionaryMain10013,759.9 ns110.77 ns1.00
TestSelectParallelToDictionaryPR10014,346.2 ns179.50 ns1.04
TestWhereSelectParallelToDictionaryMain10015,354.5 ns148.65 ns1.00
TestWhereSelectParallelToDictionaryPR10016,238.8 ns137.54 ns1.06
TestParallelToDictionaryMain100022,040.0 ns404.10 ns1.00
TestParallelToDictionaryPR100049,659.3 ns992.25 ns2.33
TestSelectParallelToDictionaryMain100050,769.5 ns992.20 ns1.00
TestSelectParallelToDictionaryPR100052,010.0 ns896.11 ns1.02
TestWhereSelectParallelToDictionaryMain100052,453.1 ns496.28 ns1.00
TestWhereSelectParallelToDictionaryPR100051,200.5 ns1,087.75 ns1.05
TestParallelToDictionaryMain10000317,249.3 ns4,007.57 ns1.00
TestParallelToDictionaryPR10000598,908.9 ns3,963.41 ns1.89
TestSelectParallelToDictionaryMain10000552,960.2 ns9,053.46 ns1.00
TestSelectParallelToDictionaryPR10000599,659.8 ns3,316.79 ns1.08
TestWhereSelectParallelToDictionaryMain10000560,577.1 ns5,482.61 ns1.00
TestWhereSelectParallelToDictionaryPR10000611,083.7 ns6,500.18 ns1.09

BDN_Artifacts.zip

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
Job-DMAJRO : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-CCUEBP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain168.87 ns0.774 ns1.00
TestParallelToDictionaryPR19,353.72 ns182.088 ns135.81
TestSelectParallelToDictionaryMain19,613.30 ns187.263 ns1.00
TestSelectParallelToDictionaryPR19,438.78 ns185.942 ns0.98
TestWhereSelectParallelToDictionaryMain110,173.87 ns202.386 ns1.00
TestWhereSelectParallelToDictionaryPR111,065.01 ns217.562 ns1.10
TestParallelToDictionaryMain10235.89 ns2.557 ns1.00
TestParallelToDictionaryPR109,453.04 ns182.520 ns40.04
TestSelectParallelToDictionaryMain109,254.72 ns157.309 ns1.00
TestSelectParallelToDictionaryPR1010,072.27 ns199.426 ns1.11
TestWhereSelectParallelToDictionaryMain1010,812.37 ns264.585 ns1.00
TestWhereSelectParallelToDictionaryPR1011,822.02 ns200.344 ns1.11
TestParallelToDictionaryMain1001,676.41 ns26.051 ns1.00
TestParallelToDictionaryPR10013,394.86 ns256.131 ns7.99
TestSelectParallelToDictionaryMain10012,813.12 ns255.738 ns1.00
TestSelectParallelToDictionaryPR10013,425.19 ns240.527 ns1.05
TestWhereSelectParallelToDictionaryMain10013,975.55 ns271.767 ns1.00
TestWhereSelectParallelToDictionaryPR10014,356.32 ns286.720 ns1.03
TestParallelToDictionaryMain100014,119.17 ns175.553 ns1.00
TestParallelToDictionaryPR100033,632.66 ns655.722 ns2.39
TestSelectParallelToDictionaryMain100031,916.77 ns507.908 ns1.00
TestSelectParallelToDictionaryPR100032,717.81 ns633.848 ns1.02
TestWhereSelectParallelToDictionaryMain100034,647.44 ns684.606 ns1.00
TestWhereSelectParallelToDictionaryPR100042,381.94 ns2,569.036 ns1.28
TestParallelToDictionaryMain10000216,167.31 ns341.834 ns1.00
TestParallelToDictionaryPR10000383,979.18 ns6,465.315 ns1.78
TestSelectParallelToDictionaryMain10000375,850.28 ns4,573.328 ns1.00
TestSelectParallelToDictionaryPR10000396,121.31 ns5,709.440 ns1.05
TestWhereSelectParallelToDictionaryMain10000376,878.77 ns7,402.242 ns1.00
TestWhereSelectParallelToDictionaryPR10000391,383.93 ns7,662.109 ns1.03

BDN_Artifacts.zip

@ericstj

Copy link
Copy Markdown
Member

It looks like @EgorBo's test results show some significant regressions. Am I reading that correctly @jozkee@stephentoub?

@stephentoub

Copy link
Copy Markdown
Member

Yes

@stephentoub

Copy link
Copy Markdown
Member

Closing per #96262 (comment). But thank you for the PR, regardless.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Linq.Parallelcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ParallelEnumerable.ToDictionary does not parallelize

6 participants

@lateapexearlyspeed@jozkee@stephentoub@EgorBo@EgorBot@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Make ToDictionary() selectors parallel. - #100590

Closed
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel
Closed

Make ToDictionary() selectors parallel.#100590
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel

Conversation

@lateapexearlyspeed

Copy link
Copy Markdown
Contributor

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 3, 2024
@jozkee

Copy link
Copy Markdown
Member

As stated in #96262 (comment), this will likely regress cases with a trivial key selector. @lateapexearlyspeed could you please provide a benchmark to see how bad it hits it so we can do an informed decision?

@jozkeejozkee added the needs-author-action An issue or pull request that requires more info or actions from the author. label May 20, 2024
@lateapexearlyspeed

Copy link
Copy Markdown
ContributorAuthor

@jozkee following is benchmark result of trivial key (and element) selector case. Toolchain in "runtime-main" is library before change and toolchain in "runtime" is library after change.

// * Summary *

BenchmarkDotNet=v0.13.1.1603-nightly, OS=Windows 10.0.22631
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
.NET SDK=8.0.202
[Host] : .NET 6.0.31 (6.0.3124.26714), X64 RyuJIT
Job-XVKCDM : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT
Job-ODFYHP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog IterationTime=250.0000 ms
MaxIterationCount=20 MinIterationCount=15 WarmupCount=1

MethodJobToolchainItemCountMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe142.00 ns9.363 ns10.782 ns35.46 ns32.76 ns62.01 ns1.000.000.0298--376 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe17,778.30 ns149.193 ns139.555 ns7,773.13 ns7,457.77 ns8,025.18 ns214.4327.420.6916--8,896 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10120.94 ns2.399 ns2.356 ns121.89 ns116.36 ns124.39 ns1.000.000.0765--960 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe108,034.68 ns190.599 ns219.495 ns8,038.56 ns7,658.90 ns8,423.41 ns66.692.110.7844--9,984 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe1001,054.74 ns94.978 ns109.377 ns1,025.83 ns905.00 ns1,335.60 ns1.000.000.60140.0073-7,576 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10010,700.76 ns295.269 ns328.191 ns10,768.11 ns10,152.59 ns11,369.07 ns10.201.001.5175--18,920 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10008,536.74 ns206.045 ns237.282 ns8,593.82 ns8,068.56 ns8,911.05 ns1.000.005.82940.6955-73,352 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe100045,359.53 ns1,780.828 ns2,050.804 ns44,628.87 ns42,440.57 ns50,316.83 ns5.310.228.32201.3587-104,118 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000175,304.48 ns5,273.794 ns6,073.309 ns174,695.64 ns166,454.45 ns186,023.27 ns1.000.00124.3351124.3351124.3351673,290 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000425,559.34 ns21,829.962 ns25,139.417 ns422,713.75 ns382,274.84 ns461,048.75 ns2.430.20131.2500131.2500123.4375848,901 B

[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}

@dotnet-policy-servicedotnet-policy-serviceBot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label May 29, 2024
@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -amd

usingSystem.Linq;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;BenchmarkRunner.Run<Tests>(args:args);publicclassTests{[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Select(i =>i).ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestWhereSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Where(i =>true).Select(i =>i).ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

@EgorBo

EgorBo commented May 29, 2024

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm]
it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args".
There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -intel -arm64

using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkRunner.Run<Tests>(args: args);
public class Tests
{
[Benchmark]
public void TestParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Select(i => i).ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestWhereSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Where(i => true).Select(i => i).ToDictionary(i => i, i => i);
}
[Params(1, 10, 100, 1000, 10000)]
public int ItemCount { get; set; }
}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

@EgorBo

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)
Example: #102805 (comment)
-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

It's correct as is (I already see 3 16-core VMs allocated for these requests😆) - it's just that currently there is no feedback that the jobs have started yet

@stephentoub

Copy link
Copy Markdown
Member

it's just that currently there is no feedback that the jobs have started yet

Ah! Ok. I'm used to the other bots that post a comment indicating that they've received the request. Thanks.

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
Job-UDSLNT : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Job-JPHOCC : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain1105.8 ns0.90 ns1.00
TestParallelToDictionaryPR18,586.0 ns47.85 ns81.20
TestSelectParallelToDictionaryMain18,611.2 ns37.32 ns1.00
TestSelectParallelToDictionaryPR18,805.7 ns72.94 ns1.02
TestWhereSelectParallelToDictionaryMain110,038.1 ns45.88 ns1.00
TestWhereSelectParallelToDictionaryPR110,348.0 ns60.22 ns1.03
TestParallelToDictionaryMain10390.3 ns3.63 ns1.00
TestParallelToDictionaryPR109,635.3 ns64.86 ns24.69
TestSelectParallelToDictionaryMain109,300.1 ns86.65 ns1.00
TestSelectParallelToDictionaryPR109,630.1 ns163.45 ns1.03
TestWhereSelectParallelToDictionaryMain1010,586.7 ns67.26 ns1.00
TestWhereSelectParallelToDictionaryPR1011,616.0 ns96.22 ns1.10
TestParallelToDictionaryMain1002,414.5 ns5.49 ns1.00
TestParallelToDictionaryPR10014,295.5 ns110.44 ns5.92
TestSelectParallelToDictionaryMain10013,759.9 ns110.77 ns1.00
TestSelectParallelToDictionaryPR10014,346.2 ns179.50 ns1.04
TestWhereSelectParallelToDictionaryMain10015,354.5 ns148.65 ns1.00
TestWhereSelectParallelToDictionaryPR10016,238.8 ns137.54 ns1.06
TestParallelToDictionaryMain100022,040.0 ns404.10 ns1.00
TestParallelToDictionaryPR100049,659.3 ns992.25 ns2.33
TestSelectParallelToDictionaryMain100050,769.5 ns992.20 ns1.00
TestSelectParallelToDictionaryPR100052,010.0 ns896.11 ns1.02
TestWhereSelectParallelToDictionaryMain100052,453.1 ns496.28 ns1.00
TestWhereSelectParallelToDictionaryPR100051,200.5 ns1,087.75 ns1.05
TestParallelToDictionaryMain10000317,249.3 ns4,007.57 ns1.00
TestParallelToDictionaryPR10000598,908.9 ns3,963.41 ns1.89
TestSelectParallelToDictionaryMain10000552,960.2 ns9,053.46 ns1.00
TestSelectParallelToDictionaryPR10000599,659.8 ns3,316.79 ns1.08
TestWhereSelectParallelToDictionaryMain10000560,577.1 ns5,482.61 ns1.00
TestWhereSelectParallelToDictionaryPR10000611,083.7 ns6,500.18 ns1.09

BDN_Artifacts.zip

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
Job-DMAJRO : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-CCUEBP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain168.87 ns0.774 ns1.00
TestParallelToDictionaryPR19,353.72 ns182.088 ns135.81
TestSelectParallelToDictionaryMain19,613.30 ns187.263 ns1.00
TestSelectParallelToDictionaryPR19,438.78 ns185.942 ns0.98
TestWhereSelectParallelToDictionaryMain110,173.87 ns202.386 ns1.00
TestWhereSelectParallelToDictionaryPR111,065.01 ns217.562 ns1.10
TestParallelToDictionaryMain10235.89 ns2.557 ns1.00
TestParallelToDictionaryPR109,453.04 ns182.520 ns40.04
TestSelectParallelToDictionaryMain109,254.72 ns157.309 ns1.00
TestSelectParallelToDictionaryPR1010,072.27 ns199.426 ns1.11
TestWhereSelectParallelToDictionaryMain1010,812.37 ns264.585 ns1.00
TestWhereSelectParallelToDictionaryPR1011,822.02 ns200.344 ns1.11
TestParallelToDictionaryMain1001,676.41 ns26.051 ns1.00
TestParallelToDictionaryPR10013,394.86 ns256.131 ns7.99
TestSelectParallelToDictionaryMain10012,813.12 ns255.738 ns1.00
TestSelectParallelToDictionaryPR10013,425.19 ns240.527 ns1.05
TestWhereSelectParallelToDictionaryMain10013,975.55 ns271.767 ns1.00
TestWhereSelectParallelToDictionaryPR10014,356.32 ns286.720 ns1.03
TestParallelToDictionaryMain100014,119.17 ns175.553 ns1.00
TestParallelToDictionaryPR100033,632.66 ns655.722 ns2.39
TestSelectParallelToDictionaryMain100031,916.77 ns507.908 ns1.00
TestSelectParallelToDictionaryPR100032,717.81 ns633.848 ns1.02
TestWhereSelectParallelToDictionaryMain100034,647.44 ns684.606 ns1.00
TestWhereSelectParallelToDictionaryPR100042,381.94 ns2,569.036 ns1.28
TestParallelToDictionaryMain10000216,167.31 ns341.834 ns1.00
TestParallelToDictionaryPR10000383,979.18 ns6,465.315 ns1.78
TestSelectParallelToDictionaryMain10000375,850.28 ns4,573.328 ns1.00
TestSelectParallelToDictionaryPR10000396,121.31 ns5,709.440 ns1.05
TestWhereSelectParallelToDictionaryMain10000376,878.77 ns7,402.242 ns1.00
TestWhereSelectParallelToDictionaryPR10000391,383.93 ns7,662.109 ns1.03

BDN_Artifacts.zip

@ericstj

Copy link
Copy Markdown
Member

It looks like @EgorBo's test results show some significant regressions. Am I reading that correctly @jozkee@stephentoub?

@stephentoub

Copy link
Copy Markdown
Member

Yes

@stephentoub

Copy link
Copy Markdown
Member

Closing per #96262 (comment). But thank you for the PR, regardless.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Linq.Parallelcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ParallelEnumerable.ToDictionary does not parallelize

6 participants

@lateapexearlyspeed@jozkee@stephentoub@EgorBo@EgorBot@ericstj
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Make ToDictionary() selectors parallel. - #100590

Closed
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel
Closed

Make ToDictionary() selectors parallel.#100590
lateapexearlyspeed wants to merge 1 commit into
dotnet:mainfrom
lateapexearlyspeed:lateapexearlyspeed-MakeToDictionarySelectorsParallel

Conversation

@lateapexearlyspeed

Copy link
Copy Markdown
Contributor

@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 3, 2024
@jozkee

Copy link
Copy Markdown
Member

As stated in #96262 (comment), this will likely regress cases with a trivial key selector. @lateapexearlyspeed could you please provide a benchmark to see how bad it hits it so we can do an informed decision?

@jozkeejozkee added the needs-author-action An issue or pull request that requires more info or actions from the author. label May 20, 2024
@lateapexearlyspeed

Copy link
Copy Markdown
ContributorAuthor

@jozkee following is benchmark result of trivial key (and element) selector case. Toolchain in "runtime-main" is library before change and toolchain in "runtime" is library after change.

// * Summary *

BenchmarkDotNet=v0.13.1.1603-nightly, OS=Windows 10.0.22631
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
.NET SDK=8.0.202
[Host] : .NET 6.0.31 (6.0.3124.26714), X64 RyuJIT
Job-XVKCDM : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT
Job-ODFYHP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT

PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable,-bl:benchmarkdotnet.binlog IterationTime=250.0000 ms
MaxIterationCount=20 MinIterationCount=15 WarmupCount=1

MethodJobToolchainItemCountMeanErrorStdDevMedianMinMaxRatioRatioSDGen 0Gen 1Gen 2Allocated
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe142.00 ns9.363 ns10.782 ns35.46 ns32.76 ns62.01 ns1.000.000.0298--376 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe17,778.30 ns149.193 ns139.555 ns7,773.13 ns7,457.77 ns8,025.18 ns214.4327.420.6916--8,896 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10120.94 ns2.399 ns2.356 ns121.89 ns116.36 ns124.39 ns1.000.000.0765--960 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe108,034.68 ns190.599 ns219.495 ns8,038.56 ns7,658.90 ns8,423.41 ns66.692.110.7844--9,984 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe1001,054.74 ns94.978 ns109.377 ns1,025.83 ns905.00 ns1,335.60 ns1.000.000.60140.0073-7,576 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10010,700.76 ns295.269 ns328.191 ns10,768.11 ns10,152.59 ns11,369.07 ns10.201.001.5175--18,920 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10008,536.74 ns206.045 ns237.282 ns8,593.82 ns8,068.56 ns8,911.05 ns1.000.005.82940.6955-73,352 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe100045,359.53 ns1,780.828 ns2,050.804 ns44,628.87 ns42,440.57 ns50,316.83 ns5.310.228.32201.3587-104,118 B
TestParallelToDictionaryJob-XVKCDM\runtime-main\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000175,304.48 ns5,273.794 ns6,073.309 ns174,695.64 ns166,454.45 ns186,023.27 ns1.000.00124.3351124.3351124.3351673,290 B
TestParallelToDictionaryJob-ODFYHP\runtime\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\CoreRun.exe10000425,559.34 ns21,829.962 ns25,139.417 ns422,713.75 ns382,274.84 ns461,048.75 ns2.430.20131.2500131.2500123.4375848,901 B

[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}

@dotnet-policy-servicedotnet-policy-serviceBot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label May 29, 2024
@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -amd

usingSystem.Linq;usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;BenchmarkRunner.Run<Tests>(args:args);publicclassTests{[Benchmark]publicvoidTestParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Select(i =>i).ToDictionary(i =>i, i =>i);}[Benchmark]publicvoidTestWhereSelectParallelToDictionary(){IEnumerable<int>collection=Enumerable.Range(0,ItemCount);Dictionary<int,int>_=collection.AsParallel().Where(i =>true).Select(i =>i).ToDictionary(i =>i, i =>i);}[Params(1,10,100,1000,10000)]publicintItemCount{get;set;}}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

@EgorBo

EgorBo commented May 29, 2024

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm]
it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args".
There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

@stephentoub

Copy link
Copy Markdown
Member

@EgorBot -intel -arm64

using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkRunner.Run<Tests>(args: args);
public class Tests
{
[Benchmark]
public void TestParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Select(i => i).ToDictionary(i => i, i => i);
}
[Benchmark]
public void TestWhereSelectParallelToDictionary()
{
IEnumerable<int> collection = Enumerable.Range(0, ItemCount);
Dictionary<int, int> _ = collection.AsParallel().Where(i => true).Select(i => i).ToDictionary(i => i, i => i);
}
[Params(1, 10, 100, 1000, 10000)]
public int ItemCount { get; set; }
}

@stephentoub

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)

Example: #102805 (comment)

-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

@EgorBo

Copy link
Copy Markdown
Member

@EgorBo, what's the invocation syntax for your bot?

I typically use -intel -arm64 -profiler [the rest of the args are directly passed to BDN app e.g. --disasm] it means "run for Intel (Xeon) and Arm64 (Ampere), with profiler and with the given BDN args". There is also -amd if you need AMD Epyc (Milano) specific results. All args are optional (-intel is used by default when no target specified, mostly, becuase it's the fastest VM instance I have)
Example: #102805 (comment)
-profiler is not useful when you have multiple [Benchmark]s.

Thanks. What am I doing wrong that it's not kicking in?

It's correct as is (I already see 3 16-core VMs allocated for these requests😆) - it's just that currently there is no feedback that the jobs have started yet

@stephentoub

Copy link
Copy Markdown
Member

it's just that currently there is no feedback that the jobs have started yet

Ah! Ok. I'm used to the other bots that post a comment indicating that they've received the request. Thanks.

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Unknown processor
Job-UDSLNT : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
Job-JPHOCC : .NET 9.0.0 (42.42.42.42424), Arm64 RyuJIT AdvSIMD
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain1105.8 ns0.90 ns1.00
TestParallelToDictionaryPR18,586.0 ns47.85 ns81.20
TestSelectParallelToDictionaryMain18,611.2 ns37.32 ns1.00
TestSelectParallelToDictionaryPR18,805.7 ns72.94 ns1.02
TestWhereSelectParallelToDictionaryMain110,038.1 ns45.88 ns1.00
TestWhereSelectParallelToDictionaryPR110,348.0 ns60.22 ns1.03
TestParallelToDictionaryMain10390.3 ns3.63 ns1.00
TestParallelToDictionaryPR109,635.3 ns64.86 ns24.69
TestSelectParallelToDictionaryMain109,300.1 ns86.65 ns1.00
TestSelectParallelToDictionaryPR109,630.1 ns163.45 ns1.03
TestWhereSelectParallelToDictionaryMain1010,586.7 ns67.26 ns1.00
TestWhereSelectParallelToDictionaryPR1011,616.0 ns96.22 ns1.10
TestParallelToDictionaryMain1002,414.5 ns5.49 ns1.00
TestParallelToDictionaryPR10014,295.5 ns110.44 ns5.92
TestSelectParallelToDictionaryMain10013,759.9 ns110.77 ns1.00
TestSelectParallelToDictionaryPR10014,346.2 ns179.50 ns1.04
TestWhereSelectParallelToDictionaryMain10015,354.5 ns148.65 ns1.00
TestWhereSelectParallelToDictionaryPR10016,238.8 ns137.54 ns1.06
TestParallelToDictionaryMain100022,040.0 ns404.10 ns1.00
TestParallelToDictionaryPR100049,659.3 ns992.25 ns2.33
TestSelectParallelToDictionaryMain100050,769.5 ns992.20 ns1.00
TestSelectParallelToDictionaryPR100052,010.0 ns896.11 ns1.02
TestWhereSelectParallelToDictionaryMain100052,453.1 ns496.28 ns1.00
TestWhereSelectParallelToDictionaryPR100051,200.5 ns1,087.75 ns1.05
TestParallelToDictionaryMain10000317,249.3 ns4,007.57 ns1.00
TestParallelToDictionaryPR10000598,908.9 ns3,963.41 ns1.89
TestSelectParallelToDictionaryMain10000552,960.2 ns9,053.46 ns1.00
TestSelectParallelToDictionaryPR10000599,659.8 ns3,316.79 ns1.08
TestWhereSelectParallelToDictionaryMain10000560,577.1 ns5,482.61 ns1.00
TestWhereSelectParallelToDictionaryPR10000611,083.7 ns6,500.18 ns1.09

BDN_Artifacts.zip

@EgorBot

Copy link
Copy Markdown
BenchmarkDotNet v0.13.12, Ubuntu 22.04.4 LTS (Jammy Jellyfish)
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
Job-DMAJRO : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job-CCUEBP : .NET 9.0.0 (42.42.42.42424), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
MethodToolchainItemCountMeanErrorRatio
TestParallelToDictionaryMain168.87 ns0.774 ns1.00
TestParallelToDictionaryPR19,353.72 ns182.088 ns135.81
TestSelectParallelToDictionaryMain19,613.30 ns187.263 ns1.00
TestSelectParallelToDictionaryPR19,438.78 ns185.942 ns0.98
TestWhereSelectParallelToDictionaryMain110,173.87 ns202.386 ns1.00
TestWhereSelectParallelToDictionaryPR111,065.01 ns217.562 ns1.10
TestParallelToDictionaryMain10235.89 ns2.557 ns1.00
TestParallelToDictionaryPR109,453.04 ns182.520 ns40.04
TestSelectParallelToDictionaryMain109,254.72 ns157.309 ns1.00
TestSelectParallelToDictionaryPR1010,072.27 ns199.426 ns1.11
TestWhereSelectParallelToDictionaryMain1010,812.37 ns264.585 ns1.00
TestWhereSelectParallelToDictionaryPR1011,822.02 ns200.344 ns1.11
TestParallelToDictionaryMain1001,676.41 ns26.051 ns1.00
TestParallelToDictionaryPR10013,394.86 ns256.131 ns7.99
TestSelectParallelToDictionaryMain10012,813.12 ns255.738 ns1.00
TestSelectParallelToDictionaryPR10013,425.19 ns240.527 ns1.05
TestWhereSelectParallelToDictionaryMain10013,975.55 ns271.767 ns1.00
TestWhereSelectParallelToDictionaryPR10014,356.32 ns286.720 ns1.03
TestParallelToDictionaryMain100014,119.17 ns175.553 ns1.00
TestParallelToDictionaryPR100033,632.66 ns655.722 ns2.39
TestSelectParallelToDictionaryMain100031,916.77 ns507.908 ns1.00
TestSelectParallelToDictionaryPR100032,717.81 ns633.848 ns1.02
TestWhereSelectParallelToDictionaryMain100034,647.44 ns684.606 ns1.00
TestWhereSelectParallelToDictionaryPR100042,381.94 ns2,569.036 ns1.28
TestParallelToDictionaryMain10000216,167.31 ns341.834 ns1.00
TestParallelToDictionaryPR10000383,979.18 ns6,465.315 ns1.78
TestSelectParallelToDictionaryMain10000375,850.28 ns4,573.328 ns1.00
TestSelectParallelToDictionaryPR10000396,121.31 ns5,709.440 ns1.05
TestWhereSelectParallelToDictionaryMain10000376,878.77 ns7,402.242 ns1.00
TestWhereSelectParallelToDictionaryPR10000391,383.93 ns7,662.109 ns1.03

BDN_Artifacts.zip

@ericstj

Copy link
Copy Markdown
Member

It looks like @EgorBo's test results show some significant regressions. Am I reading that correctly @jozkee@stephentoub?

@stephentoub

Copy link
Copy Markdown
Member

Yes

@stephentoub

Copy link
Copy Markdown
Member

Closing per #96262 (comment). But thank you for the PR, regardless.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 28, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Linq.Parallelcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ParallelEnumerable.ToDictionary does not parallelize

6 participants

@lateapexearlyspeed@jozkee@stephentoub@EgorBo@EgorBot@ericstj