我正在学习F#,关于这种语言我最关心的一件事就是表现.我写了一个小基准,我将惯用的F#与用同一种语言编写的命令式代码进行比较 - 令我惊讶的是,功能版本的出现速度明显更快.
基准包括:
这是代码:
open System
open System.IO
open System.Diagnostics
let reverseString(str:string) =
new string(Array.rev(str.ToCharArray()))
let CSharpStyle() =
let lines = File.ReadAllLines("text.txt")
for i in 0 .. lines.Length - 1 do
lines.[i] <- reverseString(lines.[i])
File.WriteAllLines("text.txt", lines)
let FSharpStyle() =
File.ReadAllLines("text.txt")
|> Seq.map reverseString
|> (fun lines -> File.WriteAllLines("text.txt", lines))
let benchmark func message =
// initial call for warm-up
func()
let sw = Stopwatch.StartNew()
for i in 0 .. 19 do
func()
printfn message sw.ElapsedMilliseconds
[<EntryPoint>] …Run Code Online (Sandbox Code Playgroud) 我最近一直在测试for循环与C#中的foreach循环的性能,我注意到,为了将一个int数组合成一个long,foreach循环可能实际上更快.这是完整的测试程序,我使用了Visual Studio 2012,x86,发布模式,优化.
这是两个循环的汇编代码.foreach:
long sum = 0;
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 xor ebx,ebx
00000008 xor edi,edi
foreach (var i in collection) {
0000000a xor esi,esi
0000000c cmp dword ptr [ecx+4],0
00000010 jle 00000025
00000012 mov eax,dword ptr [ecx+esi*4+8]
sum += i;
00000016 mov edx,eax
00000018 sar edx,1Fh
0000001b add ebx,eax
0000001d adc edi,edx
0000001f inc esi
foreach (var i in collection) {
00000020 cmp dword …Run Code Online (Sandbox Code Playgroud) 我注意到静态方法在F#中比C#更受欢迎.在C#中,您总是通过调用实例方法向集合添加元素:
mySet.Add(elem);
Run Code Online (Sandbox Code Playgroud)
但是在F#中通常有一个等效的静态方法:
mySet.Add(elem)
// OR
Set.Add elem mySet
Run Code Online (Sandbox Code Playgroud)
而且我经常在样本中看到后一种形式.在我看来,两者在语义和功能上完全相同,但是来自C#背景,使用实例方法感觉更自然.哪个是F#更好的风格?为什么?
我有一个看起来有点像这样的C#方法:
bool Eval() {
// do some work
if (conditionA) {
// do some work
if (conditionB) {
// do some work
if (conditionC) {
// do some work
return true;
}
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
在F#中,由于强制性的其他分支,这最终看起来有点丑陋:
let eval() =
// do some work
if conditionA then
// do some work
if conditionB then
// do some work
if conditionC then
// do some work
true
else
false
else
false
else
false
Run Code Online (Sandbox Code Playgroud)
用F#写这个更干净的方法是什么?
我有一个像这样的C++/CLI类:
// MyClass.h
#pragma once
namespace MyNamespace {
using namespace System;
public ref class MyClass {
private:
MyClass();
IntPtr m_ptr;
};
}
// MyClass.cpp
#include "MyClass.h"
using namespace System;
namespace MyNamespace {
MyClass::MyClass() {
m_ptr = IntPtr::Zero;
}
}
Run Code Online (Sandbox Code Playgroud)
项目编译时没有错误或警告,但是该行m_ptr = IntPtr::Zero总是带有下划线红色,并带有IntelliSense错误:"引用不能绑定到initonly字段".是什么赋予了?我怎么能摆脱这个?
这是在Visual Studio 2012 Premium Edition中,但Platform Toolset是Visual Studio 2008(v90).
考虑以下程序:
[<Struct>]
type Grid2D<'T> =
val RowLength : int
val Data : 'T[]
new(rowLength, data) = { RowLength = rowLength; Data = data }
member this.Item
with get(rowIndex, columnIndex) =
this.Data.[rowIndex * this.RowLength + columnIndex]
and set(rowIndex, columnIndex) value =
this.Data.[rowIndex * this.RowLength + columnIndex] <- value
let g = Grid2D(3, Array.zeroCreate(3 * 3))
g.[1, 1] <- 4
Run Code Online (Sandbox Code Playgroud)
最后一行无法编译:
错误FS0256:值必须是可变的才能改变内容或获取值类型的地址,例如'let mutable x = ...'
但是,如果[<Struct>]删除该属性,并且Grid2D因此是引用类型,则程序将编译.
有趣的是,手动内联属性setter也很好:
g.Data.[1 * g.RowLength + 1] <- 4
Run Code Online (Sandbox Code Playgroud)
那么为什么称它为编译错误?
注意:我知道存在此编译器错误,因此无法通过设置其中一个字段来改变结构的非可变值.但我显然没有在这里改变结构.
我们有一个函数,可以将类似的事情Int32.TryParse从使用byref 转换为使用Option作为返回值。
let inline ToOptionFunc refFunction x =
match refFunction x with
| true, value -> Some value
| false, _ -> None
Run Code Online (Sandbox Code Playgroud)
像这样的东西由于对TryParse的新重载而停止在.NET Core中进行编译:
let Int32TryParse (x:string) =
ToOptionFunc Int32.TryParse x // A unique overload for method 'TryParse' could not be determined (...)
Run Code Online (Sandbox Code Playgroud)
我尝试了很多事情,并通过这样写来偶然地使它起作用:
let Int32TryParse (x:string) =
x |> ToOptionFunc Int32.TryParse
Run Code Online (Sandbox Code Playgroud)
我只是不明白为什么编译,而前者却不编译。
我正在尝试使用ffmpeg中的一些函数,并且遇到了弹性链接器错误.这是我做的:
这是我的main.cpp:
#include "avformat.h"
int main()
{
av_register_all();
}
Run Code Online (Sandbox Code Playgroud)
这失败了:
错误LNK2019:函数_main中引用的未解析的外部符号"void __cdecl av_register_all(void)"(?av_register_all @@ YAXXZ)
我该如何解决这个错误?
我刚刚开始使用Visual C++ 2012的SSE内在函数,我需要一些指针(没有双关语).
我有两个signed short每个包含4个的数组(每个数组因此是64位,总共128个).我想将一个加载到XMM寄存器的高位,另一个加载到低位.我可以使用SSE内在函数有效地实现这一目标吗?如果是这样,怎么样?
我正在使用 D3DImage 显示一系列帧,这些帧依次渲染到同一个 Direct3D Surface 上。我目前的逻辑是:
这种方法的问题在于,当我们在 D3DImage 上调用 Unlock() 后,图像实际上并未被复制,它只是计划在下一个 WPF 渲染时复制。因此,我们有可能在 WPF 有机会显示新帧之前在 Direct3D 表面上渲染它。最终结果是我们在显示屏上看到丢失的帧。
现在,我正在尝试使用单独的 Direct3D 纹理进行渲染,并在显示之前执行到“显示纹理”的复制,这提供了更好的结果,但会产生大量开销。最好能够知道 D3DImage 何时完成刷新并立即开始渲染下一帧。这可能吗,如果可以的话怎么办?或者你有更好的主意吗?
谢谢。