有关如何在运行时设置搜索目录的SO有一个很好的答案DllImport.使用两行代码可以正常工作.
但是,许多开源项目改为使用LoadLibrary函数.有传言称通过委托调用本机方法的速度较慢.我把它们称为"谣言",因为我只在两个地方看过这个,这无论如何都是微优化.
最有趣的地方是这篇博文:http://ybeernet.blogspot.com/2011/03/techniques-of-calling-unmanaged-code.html
在那里,作者测量了不同技术的表现:
NNanomsg使用功能的代表,但提到的博客文章与评论"的这比传统的P中的性能的影响/ Invoke的,显然不是好"在这条线.
来自MSFT的ASP vNext的Kestrel服务器使用与Libuv库相同的技术:这是代码
我认为代理使用比简单的DllImport更麻烦,并且考虑到性能差异,我想知道为什么面向性能的库使用委托代替设置dll搜索文件夹?
是否有任何技术原因,如安全性,灵活性或其他 - 或者这仅仅是品味问题?我不明白其理由 - 作者是否可能没有足够的搜索StackOverflow!?
我正在阅读Interactive Extensions的源代码,并找到了一条我无法理解的行:
public static Task<bool> UsingEnumerator(this Task<bool> task, IDisposable disposable)
{
task.ContinueWith(t =>
{
if (t.IsFaulted)
{
var ignored = t.Exception; // don't remove!
}
if (t.IsFaulted || t.IsCanceled || !t.Result)
disposable.Dispose();
}, TaskContinuationOptions.ExecuteSynchronously);
return task;
}
Run Code Online (Sandbox Code Playgroud)
我也没有在文档IsFaulted或Exception属性中看到任何相关的评论.
为什么var ignored = t.Exception; // don't remove!在这种情况下需要这一行?
一个相关的问题:我认为在发布模式下这些行已被优化,但鉴于此处的注释和意图并非如此(如果代码是正确的).那么为什么这条线保持在发布模式?
代码:
#time "on"
let newVector = [|
for v in 1..10000000 ->
v |]
let newVector2 =
let a = Array.zeroCreate 10000000
for v in 1..10000000 do
a.[v-1] <- v
a
let newVector3 =
let a = System.Collections.Generic.List() // do not set capacity
for v in 1..10000000 do
a.Add(v)
a.ToArray()
Run Code Online (Sandbox Code Playgroud)
给出FSI的时间:
--> Timing now on
>
Real: 00:00:01.121, CPU: 00:00:01.156, GC gen0: 4, gen1: 4, gen2: 4
val newVector : int [] = [|1; 2; 3; 4; ...|]
>
Real: …Run Code Online (Sandbox Code Playgroud) 我广泛使用基于并行数组(SCG.SortedList<K,V>看起来像Outer<K, Inner<K_delta,V>>)的嵌套数据结构和一个复制结构的计算引擎.结构的大小可能非常不同,其中许多都是LOH,因为 - 即使它们已经嵌套 - 内部或外部的长度足够长,值大多为双倍(对于双倍,限制为1000个元素)每个数组后,它进入LOH,至少在x86上).
嵌套数据结构的用例是在长时间运行的过程中累积高频数据.我可以使用它作为缓冲区来聚合数据,只保留聚合所需的最小窗口(通过删除较旧的内部列表并修剪外部列表),但这种复制/修剪本身可能会产生LOH碎片问题并占用更多内存而不是保存它.
在深入阅读LOH碎片后,我可以推断,在我的情况下,我会有LOH碎片,因为在我的过程/计算中经常发生的事情正是在描述中,例如,一篇关于Andrew Hunter的LOH碎片的伟大文章:创造,成长通过随机增量,复制数组......
但是,我无法理解64位平台上的LOH碎片是否存在问题?在对同一篇文章的最后评论中,一位评论者认为,在64位平台上,LOH碎片几乎不是问题,因为地址空间太大,实际上很难用尽它,而内存空洞/空页不支持通过真实记忆.(另一个选择是MS在设计GC时失败了).
有些专家可以确认评论中的陈述是否适用于.NET托管内存?在大多数情况下,由于极大的地址空间,64位系统上的LOH碎片是不是应该担心?在写这个问题时,我已经找到了对C++的确认,所以这个问题专门针对.NET中的托管内存.
第二个问题是它如何适用于在64位系统上运行的32位进程?这两者是否同样适用,或者如果存在LOH碎片,32位进程可能会快速耗尽内存?(例如,对于Excel加载项,即使在64位系统上,由于传统的加载项很长时间,我也被限制为32位架构)
链接文章的评论如下:
页面缓存发布者:TruePath发布日期:2011年11月24日星期四上午6:50消息:
您使用的是不支持64位寻址的旧操作系统/ CPU(或win 7的廉价版本),或者MS从根本上无法正确利用64位寻址.
Win 7终极版允许一个进程地址高达192演出,雪豹16TB和Linux 32艾字节.你永远不会真实地咀嚼LOH中的整个地址空间.因此,MS为分配实施的策略听起来像是正确的策略,而且只是一些人为的限制正在阻碍.
请记住,因为您已经分配了一页内存并不意味着操作系统必须始终使用一页RAM来备份.操作系统完全可以自由地将页面交换到磁盘或保留空白页面.LOH应该为每个对象分配整数个psges(4K).当GC释放LOH中的对象时,应该将分配给它的页面返回给操作系统,这样它们就不再需要任何后备存储,也不会占用磁盘空间或使页面分配结构变形.
实际上,64字节系统上的LOH应该比规范堆更快且资源更少,因为没有对象被复制并且所有对象都获得整数页.与regulsr堆不同,碎片不是真正的问题,因为硬件支持的页表会为您处理.实际上,在达到虚拟内存限制之前,从不GC到LOH可能是最佳的.
确实,这样的策略最终会将LOH的大部分内容写入磁盘,但这会在第二个并发进程中发生.只要你没有在LOH中分配对象并且弄脏他们的页面的速度比你的磁盘写的速度快,你就不应该看到任何减速,除了磁盘IO的小竞争和较大的OS页面映射的小影响.系统不会崩溃,因为大多数页面确实是免费的,因此永远不会再从磁盘读回.如果LOH中没有GC标记对象,则不会发生GC的错误页面访问.因此,页面缓存使用的LIFO算法是一个相当不错的GC,它可以为某些磁盘写入和(可能)偶尔读取交换GC开销.
我想将LOH中的对象的GC元数据和任何嵌入式指针保存在与其余数据不同的页面上会更好(如果你愿意,它可以在它之前,页面的其余部分可以用于其他堆/ metadata)因此GC仍然可以释放LOH中的页面而不会触发任何不需要的页面加载.由于LOH中的对象几乎没有任何指针成员/元素(或者都是指针并且必须由GC扫描),因此可以将这些对象与数据隔离并获得两全其美:无磁盘写入且无错误页面加载对于GC.
更新:假设存在LOH碎片.问题是关于内存地址空间碎片对x64平台上的实际内存的影响,以及它在x64上运行的32位进程中的工作方式.
问题不在于如何避免它/处理它以及使用什么数据结构(文章讨论了这个).我已经做了很多测试,发现嵌套排序列表比不可变结构快5倍以上,并且通过在内部列表中使用键delta(uint16 vs int64)将我的数据压缩c.40%,而IntMap/AVL树每个键/值对占用70/50字节的开销.非常逼真的1000万对我更喜欢嵌套SL.因此,预期/可能的LOH碎片是为速度和天真的内存压缩付出的代价.我无法全面测试但由于碎片导致多少内存实际上"泄漏",但从我读过的内容中我有理由怀疑是否存在任何泄漏.
我想IEnumerable<KeyValuePair<DateTime, 'T>>在我自己的类中实现并向该类添加数学运算符,以便运算符可以像任何数值类型的内联函数一样工作'T- 自动添加约束.
我只是无法使下面的代码工作.在成员声明中,它既不能使用也不能使用'inline'关键字.
另外,如果我定义一个函数
let inline add l r = l + r
Run Code Online (Sandbox Code Playgroud)
在类型之前使用它而不是添加l.Value + r.Value,它也不起作用.
有人可以告诉我我做错了什么吗?
可能整个方法都是错误的,并且有另一种方法可以实现相同的目标吗?
namespace Test
open System
open System.Linq
open System.Collections.Generic
[<SerializableAttribute>]
type TimeSeries<'T>(dictionary : IDictionary<DateTime, 'T>) =
let internalList = new SortedList<DateTime, 'T>(dictionary)
interface IEnumerable<KeyValuePair<DateTime, 'T>> with
member this.GetEnumerator() = internalList.GetEnumerator()
member this.GetEnumerator() : Collections.IEnumerator
= internalList.GetEnumerator() :> Collections.IEnumerator
member private this.sl = internalList
static member inline (+) (left : TimeSeries<'T>, right : TimeSeries<'T>) =
let res =
query …Run Code Online (Sandbox Code Playgroud) 我目前正在优化一个低级库,并发现了一个反直觉的案例.导致此问题的提交就在这里.
有代表
public delegate void FragmentHandler(UnsafeBuffer buffer, int offset, int length, Header header);
Run Code Online (Sandbox Code Playgroud)
和一个实例方法
public void OnFragment(IDirectBuffer buffer, int offset, int length, Header header)
{
_totalBytes.Set(_totalBytes.Get() + length);
}
Run Code Online (Sandbox Code Playgroud)
在这一行中,如果我将该方法用作委托,程序会为临时委托包装器分配许多GC0,但性能提高10%(但不稳定).
var fragmentsRead = image.Poll(OnFragment, MessageCountLimit);
Run Code Online (Sandbox Code Playgroud)
如果我改为将方法缓存在循环外的委托中,如下所示:
FragmentHandler onFragmentHandler = OnFragment;
Run Code Online (Sandbox Code Playgroud)
然后程序根本没有分配,数字非常稳定,但速度要慢得多.
我查看了生成的IL并且它正在执行相同的操作,但在后一种情况下newobj只调用一次然后加载局部变量.
使用缓存的委托IL_0034:
IL_002d: ldarg.0
IL_002e: ldftn instance void Adaptive.Aeron.Samples.IpcThroughput.IpcThroughput/Subscriber::OnFragment(class [Adaptive.Agrona]Adaptive.Agrona.IDirectBuffer, int32, int32, class [Adaptive.Aeron]Adaptive.Aeron.LogBuffer.Header)
IL_0034: newobj instance void [Adaptive.Aeron]Adaptive.Aeron.LogBuffer.FragmentHandler::.ctor(object, native int)
IL_0039: stloc.3
IL_003a: br.s IL_005a
// loop start (head: IL_005a)
IL_003c: ldloc.0 …Run Code Online (Sandbox Code Playgroud) 我已经花了几个小时试图完成这项工作,并觉得我错过了一些简单的事情:
my_env = new.env(hash = TRUE, parent = .GlobalEnv)
my_env[['echo']] <- function(x) {x}
my_env[['echo']](123)
[1] 123
my_env$echo(123)
[1] 123
save(my_env, file = "MyEnv.RData", envir = .GlobalEnv)
loaded_env <- load(file = "MyEnv.RData",envir = .GlobalEnv)
typeof(loaded_env)
[1] "character"
Run Code Online (Sandbox Code Playgroud)
当我保存整个工作区时,保存函数然后加载回来(在我关闭/打开R Studio之后).但是在这里,save()和/或load()不起作用,加载后我的环境中只有一个字符串.
如何将单独的环境对象保存到文件中,而不是完整的工作区?然后我需要将该环境(my_env)中的所有对象加载到另一个会话中的.GlobalEnv中.
我找到了Don Syme 的演示文稿,其中显示了Erlang的演示文稿
fac(0) -> 1
fac(N) -> N * fac(N-1).
Run Code Online (Sandbox Code Playgroud)
相当于F#的
let rec fac = function
| 0 -> 1
| n -> n * fac (n-1)
Run Code Online (Sandbox Code Playgroud)
但看起来没有办法在不损失类型安全的情况下为不同的arity使用模式匹配.例如,可以使用列表模式匹配,但是类型必须是公共基类型(例如object):
let concat = function
| [x;y] -> x.ToString() + y.ToString()
| [x] -> x.ToString()
Run Code Online (Sandbox Code Playgroud)
鉴于在模块F#函数不支持过载,它看起来像改写二郎代码到F#静态类型的唯一方法是使用静态类与方法重载的替代模块.有没有更好的方法在F#中使用不同的arity重写Erlang函数?
在一般情况下,是正确地说,Erlang的参数匹配更接近.NET的(包括C#)方法重载,而不是F#的模式匹配?或者两者之间没有直接的替代,例如在Erlang中可能存在具有不同arities +守卫的功能:
max(x) -> x.
max(x,y) when x > y -> x.
max(x,y) -> y.
max(comparer, x, y) -> if comparer(x,y) > 0 -> x; true -> y end.
Run Code Online (Sandbox Code Playgroud)
在最后一种情况下,参数是不同类型的.你会如何在F#中重写它?
此代码消耗接近零CPU(i5系列)
public void SpinWait() {
for (int i = 0; i < 10000; i++)
{
Task.Factory.StartNew(() =>
{
var sw = new SpinWait();
while (true)
{
sw.SpinOnce();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
在我的代码中,与SemaphoreSlim相比,性能差异是旋转真正合理(5 Mops)的情况下的3倍或更多.但是,我担心使用它进行长期等待.标准建议是实现两阶段等待操作.我可以检查NextSpinWillYield属性并引入一个计数器+重置来增加默认的旋转迭代而不会屈服,而不是退回到信号量.
但是,仅仅SpinWait.SpinOnce用于长期等待的缺点是什么?我已经查看了它的实现,并在需要时正确地生成了它.它使用Thread.SpinWait现代CPU使用PAUSE指令,并且根据英特尔的说法非常有效.
我在监视任务管理器时发现的一个问题是,由于默认的ThreadPool算法逐渐增加线程数(它在所有任务繁忙时每秒添加一个线程).这可以通过使用来解决ThreadPool.SetMaxThreads,然后修复线程数并且CPU使用率仍接近零.
如果长期等待任务的数量有限,那么使用SpinWait.SpinOnce长期等待的其他陷阱是什么.它是否依赖于CPU系列,OS,.NET版本?
(只是为了澄清:我仍然会实现两阶段等待,我只是好奇为什么不一直使用SpinOnce?)
在我第一次尝试创建类型提供程序时,我有一个消息的 ProvidedTypeDefinition:
// Message type
let mTy = ProvidedTypeDefinition(asm, ns, message.Key, Some(typeof<ValueType>),
HideObjectMethods = true, IsErased = false)
// Direct buffer
let bufferField = ProvidedField("_directBuffer", typeof<IDirectBuffer>)
mTy.AddMember bufferField
let mCtor1 =
ProvidedConstructor(
[ProvidedParameter("buffer", typeof<IDirectBuffer>)],
InvokeCode = fun args ->
match args with
| [this;buffer] ->
Expr.FieldSet (this, bufferField, <@@ %%buffer:IDirectBuffer @@>)
| _ -> failwith "wrong ctor params"
)
mTy.AddMember mCtor1
Run Code Online (Sandbox Code Playgroud)
然后我需要在另一个提供的类型的方法中创建该类型的实例。我正在这样做:
let mMethod = ProvidedMethod(message.Key, [ProvidedParameter("buffer", typeof<IDirectBuffer>)], mTy)
mMethod.InvokeCode <- (fun [this;buffer] ->
let c = mTy.GetConstructors().Last() …Run Code Online (Sandbox Code Playgroud)