"using static" 杀死 AsParallel
"using static" kills AsParallel
在下面的代码中,如果取消注释“using static”行,查询将不会运行并行。为什么?
(Visual Studio 社区 2019,.Net Core 3.1 / .Net 4.8)
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace UsingStatic_Mystery
{
//using static Enumerable;
class Program
{
static void Main(string[] args)
{
var w = new Stopwatch();
iter:
w.Start();
var xx = Enumerable.Range(0, 10)
.AsParallel()
.OrderByDescending(x => {
Thread.Sleep(new Random().Next(100));
Console.WriteLine(x);
return x;
}).ToArray();
w.Stop();
Console.WriteLine();
foreach (var x in xx) Console.WriteLine(x);
Console.WriteLine(w.ElapsedMilliseconds);
Console.ReadLine();
w.Reset();
goto iter;
}
}
}
输出,uncommented/commented:
找到:
这是带有 using static
注释的 IL code generated(所以 没有 using static
):
IL_0038: call class [System.Linq.Parallel]System.Linq.OrderedParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::OrderByDescending<int32, int32>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, class [System.Private.CoreLib]System.Func`2<!!0, !!1>)
IL_003d: call !!0[] [System.Linq.Parallel]System.Linq.ParallelEnumerable::ToArray<int32>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>)
这是 IL code generated 和 using static
未注释的(所以 和 using static
):
IL_0038: call class [System.Linq]System.Linq.IOrderedEnumerable`1<!!0> [System.Linq]System.Linq.Enumerable::OrderByDescending<int32, int32>(class [System.Private.CoreLib]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Private.CoreLib]System.Func`2<!!0, !!1>)
IL_003d: call !!0[] [System.Linq]System.Linq.Enumerable::ToArray<int32>(class [System.Private.CoreLib]System.Collections.Generic.IEnumerable`1<!!0>)
“正确”的一方使用 Parallel.OrderBy
,“错误”的一方使用 Enumerable.OrderBy
。由于这个原因,您看到的结果非常清楚。选择其中一个 OrderBy
的原因是因为使用 using static Enumerable
您声明 C# 应该更喜欢 Enumerable
class.[=52= 中的方法]
更有趣的是,你有没有像这样编写 using 块:
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using static System.Linq.Enumerable;
namespace ConsoleApp1
{
所以 在 命名空间之外,一切都会“正确”工作 (IL code generated)。
I'll say that namespace resolution works by level...首先C#尝试所有定义在最内层namespace
的using
,如果没有一个足够好则上一层namespace
。如果在同一级别 有多个候选人,则选择最佳匹配。在没有 using static
的示例和我给出的 using
+ using static
都是顶级的示例中,只有一个级别,因此 C# 是最佳候选者。在两层using
中检查了最里面的那个,using static Enumerable
足以解决OrderBy
方法,所以没有做额外的检查。
我再说一遍,SharpLab was the MVP of this response. If you have a question about what the C# compiler does under the hood, SharpLab can give you the response (technically you could use ildasm.exe or ILSpy,但是SharpLab非常直接,因为它是一个网站,你可以交互式地更改源代码). SVP(第二个有价值的球员)(对我来说)是 WinMerge,我用来比较 IL 程序集
回复评论
The namespace_name referenced by a using_namespace_directive is resolved in the same way as the namespace_or_type_name referenced by a using_alias_directive. Thus, using_namespace_directives in the same compilation unit or namespace body do not affect each other and can be written in any order.
然后
Ambiguities between multiple using_namespace_directives and using_static_directives are discussed in Using namespace directives.
所以第一条规则甚至适用于 using static
。这解释了为什么第三个例子(我的)等同于 no-using static
.
为什么ParallelEnumerable.OrderedBy()
比Enumerable.OrderBy()
都被C# 编译器检查过,很简单:
AsParallel()
returns一个ParallelQuery<TSource>
(实现IEnumerable<TSource>
)
ParallelEnumerable.OrderedBy()
签名:
public static OrderedParallelQuery<TSource> OrderBy<TSource, TKey>(this ParallelQuery<TSource> source, Func<TSource, TKey> keySelector)
Enumerable.OrderedBy()
签名:
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
第一个接受 ParallelQuery<TSource>
,与 AsParallel()
返回的类型完全相同,不需要“向下转换”。
在下面的代码中,如果取消注释“using static”行,查询将不会运行并行。为什么?
(Visual Studio 社区 2019,.Net Core 3.1 / .Net 4.8)
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace UsingStatic_Mystery
{
//using static Enumerable;
class Program
{
static void Main(string[] args)
{
var w = new Stopwatch();
iter:
w.Start();
var xx = Enumerable.Range(0, 10)
.AsParallel()
.OrderByDescending(x => {
Thread.Sleep(new Random().Next(100));
Console.WriteLine(x);
return x;
}).ToArray();
w.Stop();
Console.WriteLine();
foreach (var x in xx) Console.WriteLine(x);
Console.WriteLine(w.ElapsedMilliseconds);
Console.ReadLine();
w.Reset();
goto iter;
}
}
}
输出,uncommented/commented:
找到:
这是带有 using static
注释的 IL code generated(所以 没有 using static
):
IL_0038: call class [System.Linq.Parallel]System.Linq.OrderedParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::OrderByDescending<int32, int32>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, class [System.Private.CoreLib]System.Func`2<!!0, !!1>)
IL_003d: call !!0[] [System.Linq.Parallel]System.Linq.ParallelEnumerable::ToArray<int32>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>)
这是 IL code generated 和 using static
未注释的(所以 和 using static
):
IL_0038: call class [System.Linq]System.Linq.IOrderedEnumerable`1<!!0> [System.Linq]System.Linq.Enumerable::OrderByDescending<int32, int32>(class [System.Private.CoreLib]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Private.CoreLib]System.Func`2<!!0, !!1>)
IL_003d: call !!0[] [System.Linq]System.Linq.Enumerable::ToArray<int32>(class [System.Private.CoreLib]System.Collections.Generic.IEnumerable`1<!!0>)
“正确”的一方使用 Parallel.OrderBy
,“错误”的一方使用 Enumerable.OrderBy
。由于这个原因,您看到的结果非常清楚。选择其中一个 OrderBy
的原因是因为使用 using static Enumerable
您声明 C# 应该更喜欢 Enumerable
class.[=52= 中的方法]
更有趣的是,你有没有像这样编写 using 块:
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using static System.Linq.Enumerable;
namespace ConsoleApp1
{
所以 在 命名空间之外,一切都会“正确”工作 (IL code generated)。
I'll say that namespace resolution works by level...首先C#尝试所有定义在最内层namespace
的using
,如果没有一个足够好则上一层namespace
。如果在同一级别 有多个候选人,则选择最佳匹配。在没有 using static
的示例和我给出的 using
+ using static
都是顶级的示例中,只有一个级别,因此 C# 是最佳候选者。在两层using
中检查了最里面的那个,using static Enumerable
足以解决OrderBy
方法,所以没有做额外的检查。
我再说一遍,SharpLab was the MVP of this response. If you have a question about what the C# compiler does under the hood, SharpLab can give you the response (technically you could use ildasm.exe or ILSpy,但是SharpLab非常直接,因为它是一个网站,你可以交互式地更改源代码). SVP(第二个有价值的球员)(对我来说)是 WinMerge,我用来比较 IL 程序集
回复评论
The namespace_name referenced by a using_namespace_directive is resolved in the same way as the namespace_or_type_name referenced by a using_alias_directive. Thus, using_namespace_directives in the same compilation unit or namespace body do not affect each other and can be written in any order.
然后
Ambiguities between multiple using_namespace_directives and using_static_directives are discussed in Using namespace directives.
所以第一条规则甚至适用于 using static
。这解释了为什么第三个例子(我的)等同于 no-using static
.
为什么ParallelEnumerable.OrderedBy()
比Enumerable.OrderBy()
都被C# 编译器检查过,很简单:
AsParallel()
returns一个ParallelQuery<TSource>
(实现IEnumerable<TSource>
)
ParallelEnumerable.OrderedBy()
签名:
public static OrderedParallelQuery<TSource> OrderBy<TSource, TKey>(this ParallelQuery<TSource> source, Func<TSource, TKey> keySelector)
Enumerable.OrderedBy()
签名:
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
第一个接受 ParallelQuery<TSource>
,与 AsParallel()
返回的类型完全相同,不需要“向下转换”。