如今优化似乎是一种迷失的艺术.所有程序员都没有从代码中挤出每一盎司的效率吗?经常在雪地里行走五英里的时候这样做?
本着回归丢失的艺术的精神,您知道的简单(或复杂)变化以优化C#/ .NET代码的一些提示是什么?因为它是如此广泛,取决于一个人想要完成什么,它有助于提供你的提示的背景.例如:
StringBuilder.请参阅底部的链接以了解相关信息.string.Compare两个字符串比较,而不是做这样的事情string1.ToLower() == string2.ToLower()到目前为止,普遍的共识似乎是衡量关键.这种方式忽略了这一点:测量不会告诉你什么是错的,或者如果遇到瓶颈会怎么做.我遇到了字符串连接瓶颈一次,不知道该怎么办,所以这些提示很有用.
我甚至发布这个问题的意思是为了解决常见的瓶颈问题,以及在遇到这些问题之前如何避免它们.它甚至不一定是任何人应该盲目遵循的即插即用代码,而是更多关于获得对性能应该被考虑的理解,至少在某种程度上,并且需要注意一些常见的陷阱.
我可以看到,知道为什么提示有用以及应该应用的位置可能会有用.对于StringBuilder小费,我找到了很久以前在Jon Skeet网站上做过的帮助.
我一直在学习F#和函数式编程,并试图以功能的方式做事.但是,当我重写一些我已用C#编写的代码时,我会陷入简单的if-then语句(只做一些事情而不返回值).我知道你可以在F#中解决这个问题:
if expr then do ()
Run Code Online (Sandbox Code Playgroud)
但是,我认为这是编码的必要方法?也许我对功能编程学得不够,但它对我来说似乎没什么用.我认为功能方法是组合函数和表达式,而不是简单地一个接一个地执行语句,这是if-then似乎鼓励的.
所以,我错过了什么,如果 - 那么在功能世界中是完美的吗?如果没有,这种陈述的功能等同物是什么?我怎么能拿一个if-then然后把它变成功能呢?
编辑:我可能会问错误的问题(对不起,对于函数式编程来说仍然相当新):让我们采用一个真实世界的例子让我甚至问这个问题:
if not <| System.String.IsNullOrWhiteSpace(data) then do
let byteData = System.Text.Encoding.Unicode.GetBytes(data)
req.ContentLength <- int64 byteData.Length
let postStream : System.IO.Stream = req.GetRequestStream()
postStream.Write(byteData, 0, byteData.Length)
postStream.Flush()
postStream.Dispose()
Run Code Online (Sandbox Code Playgroud)
if-then的主体不返回任何内容,但我不知道如何使其更具功能性(如果可能的话).我不知道最小化命令式代码的正确技巧.考虑到F#的性质,直接运输我的C#相当容易,但是我很难将其转换为功能.每次我在C#中使用if语句,并且我正在尝试将其传输到F#时,我感到气馁,因为我无法想到一种方法来使代码更具功能性.
我已经看到二进制和十六进制经常使用但从未八进制.然而,八进制在某些语言中使用它有自己的约定(即,指示八进制基数的前导0).何时使用八进制?使用八进制或八进制的一些典型情况会更容易推理吗?或者仅仅是品味问题?
我今天正在阅读Joel On Software并且遇到了这个引用:
如果不理解函数式编程,就无法发明MapReduce,这种算法使Google具有如此大规模的可扩展性.术语Map和Reduce来自Lisp和函数式编程.回想起来,对于那些从6.001等效编程类中记得纯粹功能性程序没有副作用且因此可以简单地并行化的人来说,MapReduce是显而易见的.
当他说功能性程序没有副作用时,他的意思是什么?这如何使并行化变得微不足道?
我正在尝试学习F#并且在看到一些奇怪的东西(至少对我来说)时正在观看视频.有问题的视频在这里,相关部分从2:30开始,感兴趣的人.但基本上,这个人说F#使得使用数组变得很尴尬,并且设计师故意这样做,因为列表更容易"预先添加和追加".
立即浮现在脑海中的问题:在不可改变的语言中添加和追加一些应该不赞成的东西并不容易吗?具体来说,我正在考虑C#的列表,您可以在其中执行类似的操作List.Add(obj);并改变列表.使用数组,您必须创建一个全新的数组,但这也是在不可变语言中需要发生的事情.
那么为什么F#的设计师更喜欢列表呢?列表和数组之间的不可变环境的根本区别是什么?我错过了什么?F#中的列表真的是链接列表吗?
我正在开发一个使用XNA和C#的游戏,并且试图避免new struct()每帧调用类型代码,因为我认为它会让GC失败."但是等等,"我对自己说,"结构是一种价值类型.那时GC不应该被调用,对吧?" 嗯,这就是我在这里问的原因.
我对价值类型的变化只有一个非常模糊的概念.如果我在函数调用中创建一个新结构,是否在堆栈上创建了结构?它是否会被推动和弹出,性能不受打击?此外,如果我需要在一次调用中创建多个实例,是否会有一些内存限制或性能影响?
举个例子,这个代码:
spriteBatch.Draw(tex, new Rectangle(x, y, width, height), Color.White);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,Rectangle是一个结构.创建新Rectangle时会发生什么?多次重复该行(比如几千次)会有什么影响?是否创建了这个Rectangle,将一个副本发送到Draw方法,然后丢弃(意味着没有内存被吃掉,在同一个函数中以这种方式调用Draw)?
PS我知道这可能是预先成熟的优化,但我很好奇并希望更好地了解正在发生的事情.
我正在使用C#和XNA开发2D头顶射击游戏.我有一个我称之为"子弹"的类,需要在每一秒钟内更新许多这些实例.
我这样做的第一种方法是拥有一个通用的子弹列表,并根据需要简单地移除和添加新的子弹.但是在这样做的过程中,GC经常出现,我的游戏有一些周期性的生涩延迟.(很多代码被删除了,但只想展示一个简单的代码片段)
if (triggerButton)
{
bullets.Add(new bullet());
}
if (bulletDestroyed)
{
bullets.Remove(bullet);
}
Run Code Online (Sandbox Code Playgroud)
我的第二个也是当前的尝试是有一个单独的通用Stack子弹,当我完成一个子弹时我会推动它,如果堆栈中有任何东西,当我需要一个新子弹时弹出子弹.如果堆栈中没有任何内容,那么我将新的项目符号添加到列表中.它似乎减少了生涩的滞后,但又一次,有时还会出现一些生涩的滞后(尽管我不知道它是否相关).
if (triggerButton)
{
if (bulletStack.Count > 0)
{
bullet temp = bulletStack.Pop();
temp.resetPosition();
bullets.Add(temp);
}
else
{
bullets.Add(new bullet());
}
}
if (bulletDestroyed)
{
bulletStack.Push(bullet);
bullets.Remove(bullet);
}
Run Code Online (Sandbox Code Playgroud)
所以,我知道过早的优化是所有邪恶的根源,但这是非常明显的低效率,我可以提前赶上(这是在甚至不必担心敌人的子弹充满屏幕之前).所以我的问题是:将未使用的对象推送到堆栈会调用垃圾收集吗?参考文件是保持活着还是被破坏的对象?有没有更好的方法来处理更新许多不同的对象?例如,我是否太过花哨?如果只是遍历列表并找到一个未使用的子弹就可以了吗?
我经常读到可读性和可维护性的重要性.或者,我阅读了关于哪些语法功能不好或好的非常强烈的意见.或者讨论某些范式的价值观,比如OOP.
除此之外,每当我读到有关主观问题的关于SO或Meta的辩论时,同样的问题在我脑海中浮现.或者阅读有关最佳实践的问题,有时会发现自己或其他人不同意.
主观性在编程领域中扮演什么角色?
有时候我认为它起着很大的作用.软件开发人员在某种程度上是工程师,也是人.编程的很大一部分是处理人类可读的代码.这与数学或物理学或其他具有非常精确和结构化规则的学科非常不同.在这里,确切的结构和规则大部分都在空中,随心所欲地变化,因此存在的语言数量.一个人可能会发现一种语言非常易读,而另一个人可能会发现他们自己的语言最令人欣慰.
与实践相同.一个人可能不喜欢某些公认的做法.我自己发现将类分成不同的文件是非常难以理解的.
但是,我不能说规则一般没有帮助.某些做法已经并确实使生活更轻松.新语言产生了语法和结构,使生活更轻松.即使给了一大批不同的人群,代码也很容易阅读和维护.所以也许这些事情并不像我想象的那么主观.
在某种程度上,它让我想起了UI设计.当然这是主观的,但是有一个完整的学科参与制作良好的用户界面,它往往有效.
对于可维护性,可读性和其他最佳实践背后的想法,是否存在一些非主观的内容?当一个人开发新语言或想到新的实践时,有什么东西可以掌握吗?
命名空间曾经是ECMAScript(旧的ECMAScript 4)的考虑因素,但已被取出.正如Brendan Eich在这条消息中所说:
ES4中名称空间的一个用例是早期绑定(使用命名空间内在),无论是性能还是程序员理解 - 运行时名称绑定都不会与任何早期绑定不一致.但是,在任何动态代码加载方案(如Web)中的早期绑定需要使用优先级或预留机制来避免早期与晚期绑定冲突.
此外,正如一些JS实现者关注的那样,多个开放
命名空间会强加运行时成本,除非实现工作
更加困难.由于这些原因,名称空间和早期绑定(比如
它们之前的包,今年四月)必须去.
但我不确定我是否理解所有这一切.什么是优先顺序或保留机制以及为什么需要这些机制?此外,早期绑定和命名空间必须齐头并进吗?出于某种原因,我无法解决所涉及的问题.任何人都可以尝试更充实的解释吗?
另外,为什么名称空间会占用运行时成本?在我看来,我不禁看到命名空间和使用闭包的函数之间的概念差别不大.例如,雅虎和谷歌都有YAHOO和谷歌对象"行为"名称空间,因为它们包含单个访问点内的所有公共和私有变量,函数和对象.那么,为什么命名空间在实现中会有如此显着的不同呢?也许我只是误解了命名空间的确切含义.
为了赏金,我想知道两件事:
让我们说假设(读:我不认为我真的需要这个,但我很好奇,因为这个想法突然出现在我脑海中),人们想要在堆栈本地留出一堆内存,而不是在堆上.例如,像这样:
private void someFunction()
{
int[20] stackArray; //C style; I know the size and it's set in stone
}
Run Code Online (Sandbox Code Playgroud)
我猜的答案是否定的.我能找到的只是基于堆的数组.如果有人需要这个,那会有任何解决方法吗?有没有办法以"值类型"方式留出一定数量的顺序存储器?或者是具有命名参数的结构的唯一方法(就像XNA中的Matrix结构有16个命名参数(M11-M44)的方式)?
c# ×4
.net ×2
f# ×2
arrays ×1
ecma262 ×1
javascript ×1
namespaces ×1
octal ×1
optimization ×1
stack ×1
xna ×1