我发现C anc C#中类似代码之间存在巨大的性能差异.
C代码是:
#include <stdio.h>
#include <time.h>
#include <math.h>
main()
{
int i;
double root;
clock_t start = clock();
for (i = 0 ; i <= 100000000; i++){
root = sqrt(i);
}
printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
}
Run Code Online (Sandbox Code Playgroud)
而C#(控制台应用程序)是:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
DateTime startTime = DateTime.Now;
double root;
for (int i = 0; i <= 100000000; i++)
{
root = Math.Sqrt(i);
} …Run Code Online (Sandbox Code Playgroud) 在我问的另一个问题中,出现了一条评论,表明.NET框架的Array.Copy方法使用了非托管代码.我用Reflector挖掘并发现Array.Copy方法重载的签名之一定义如下:
[MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
internal static extern void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable);
Run Code Online (Sandbox Code Playgroud)
看了这个之后,我有点困惑.我混淆的来源是extern修饰符,意思是(MSDN链接):
extern修饰符用于声明从外部实现的方法.
但是,方法声明也用一个MethodImplOptions.InternalCall属性来装饰,它表示(MSDN链接):
指定内部调用.内部调用是对在公共语言运行时本身内实现的方法的调用.
任何人都可以解释这个看似明显的矛盾吗?
是否有用于十进制计算的库,尤其是Pow(decimal, decimal)方法?我找不到任何东西.
无论哪种方式,它都可以是免费的或商业的,只要有一种方式.
注意:我自己不能这样做,不能用于循环,不能使用Math.Pow,Math.Exp或者Math.Log,因为它们都采取doubles,而我不能使用doubles.我不能使用系列,因为它会像doubles 一样精确.
在我们的产品中,我们有称为"服务"的东西,它们是产品不同部分之间的基本交流方式(尤其是语言之间 - 内部语言,C,Python和.NET).
目前,代码是这样的(Services.Execute利用params object[] args):
myString = (string)Services.Execute("service_name", arg1, arg2, ...);
Run Code Online (Sandbox Code Playgroud)
我更愿意能够编写这样的代码并获得类型检查和更简洁的代码的好处:
myString = ServiceName(arg1, arg2, ...);
Run Code Online (Sandbox Code Playgroud)
这可以通过一个简单的功能来实现,
public static string ServiceName(int arg1, Entity arg2, ...)
{
return (string)Services.Execute("service_name", arg1, arg2, ...);
}
Run Code Online (Sandbox Code Playgroud)
但这是相当冗长的,并且在执行大量服务时并不那么容易管理,正如我打算做的那样.
看看如何extern和DllImportAttribute工作,我希望有可能通过这样的方式来解决这个问题:
[ServiceImport("service_name")]
public static extern string ServiceName(int arg1, Entity arg2, ...);
Run Code Online (Sandbox Code Playgroud)
但我根本不知道如何实现这一点,似乎无法找到任何文档(extern似乎是一个相当模糊的定义问题).我发现最接近的是一个有点相关的问题,如何为.NET中的extern方法提供自定义实现?无论如何,这并没有真正回答我的问题而且有些不同.C#语言规范(特别是在4.0版,第10.6.7节,外部方法中)没有帮助.
所以,我想提供外部方法的自定义实现; 这可以实现吗?如果是这样,怎么样?
我在读完这篇文章之后来到这里并且没有找到相关的答案 - 所以在你阅读整个问题之前,请不要将其标记为副本.
我一直在使用反射器并进行调查.Object.Equals我看到的是:
[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public virtual bool Equals(object obj)
{
return RuntimeHelpers.Equals(this, obj);
}
Run Code Online (Sandbox Code Playgroud)
而且RuntimeHelpers.Equals看起来是这样的:
// System.Runtime.CompilerServices.RuntimeHelpers
/// <summary>Determines whether the specified <see cref="T:System.Object" /> instances are considered equal.</summary>
/// <returns>true if the <paramref name="o1" /> parameter is the same instance as the <paramref name="o2" /> parameter, or if both are null, or if o1.Equals(o2) returns true; otherwise, false.</returns>
/// <param name="o1">The first object to …Run Code Online (Sandbox Code Playgroud) 这是一个好奇心问题.我正在看这个代码反汇编(C#,64位,发布模式,VS 2012 RC):
double a = 10d * Math.Log(20d, 2d);
000000c8 movsd xmm1,mmword ptr [00000138h]
000000d0 movsd xmm0,mmword ptr [00000140h]
000000d8 call 000000005EDC7F50
000000dd movsd mmword ptr [rsp+58h],xmm0
000000e3 movsd xmm0,mmword ptr [rsp+58h]
000000e9 mulsd xmm0,mmword ptr [00000148h]
000000f1 movsd mmword ptr [rsp+30h],xmm0
a = Math.Pow(a, 6d);
000000f7 movsd xmm1,mmword ptr [00000150h]
000000ff movsd xmm0,mmword ptr [rsp+30h]
00000105 call 000000005F758220
0000010a movsd mmword ptr [rsp+60h],xmm0
00000110 movsd xmm0,mmword ptr [rsp+60h]
00000116 movsd mmword ptr [rsp+30h],xmm0
Run Code Online (Sandbox Code Playgroud)
...并且发现奇怪的是编译器没有在此处使用x87指令(Power使用日志).当然,我不知道调用位置的代码是什么,但我知道SIMD没有Log功能,这使得这个选择更加奇怪.此外,这里什么都没有,所以为什么SIMD而不是简单的x87?
在较小的一点上,我还发现奇怪的是没有使用x87 FYL2X指令,这是专门针对第一行代码中所示的情况而设计的.
任何人都可以对此有所了解吗?
我在几个开源项目中遇到了非最佳代码,当程序员不考虑他们使用的是什么时.
两种情况之间的性能差异高达10倍,因为Math.Pow在内部使用Exp和Ln函数,在这个答案中如何解释.
在大多数情况下(通常具有较小的功率),通常的乘法优于供电,但最好的是通过平方算法的Exponentation.
因此,我认为编译器或JITter必须使用权限和其他功能执行此类优化.为什么还没有介绍?我对吗?
我想知道这一点,因为我需要继承StringBuilder来实现一个TextChanged事件.我总是可以创建一个包含private StringBuilder隐式/显式转换的包装器,但这似乎不是一个合适的解决方案.
幸运的是,我可以从写入StringBuilder的对象继承,所以这对我来说不是一个问题,但我仍然很好奇为什么这个类是密封的.
在这个链接中,我们可以看到System.Math类的源代码.但我找不到正弦定义的源代码.
这里有什么我想念的吗?
c# ×8
.net ×7
c ×2
performance ×2
.net-3.5 ×1
assembly ×1
clr ×1
decimal ×1
disassembly ×1
extern ×1
inheritance ×1
jit ×1
math ×1
math.h ×1
optimization ×1
pow ×1
refactoring ×1
sealed ×1
simd ×1