我知道 CPU 会计算所有 L1/2/3 缓存未命中,并且原则上可以访问此信息。例如,有一个来自英特尔的性能查看器。我只是在 C# 中找不到示例。可以从 .NET 访问这些数据吗?
在我第一次尝试创建类型提供程序时,我有一个消息的 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) 有没有一种简单的方法来检测 .NET Core 应用程序是从dotnet系统上安装的还是独立发行版运行的?
我正在开发一个构建自动化脚本,该脚本需要一些有关相对路径和入口点的知识,以便使用 cli 参数创建依赖进程。
我正在使用 .NET Core 并发布创建myapp.exe. 在设计和调试期间,程序使用dotnet命令运行,我使用以下命令来启动具有特定 cli 参数的另一个进程:
var filename = typeof(Program).Assembly.Location; // .../myapp.dll
var argsString = string.Join(" ", args);
var startInfo = new ProcessStartInfo
{
Arguments = filename + " " + argsString,
UseShellExecute = false,
RedirectStandardOutput = true,
FileName = "dotnet",
CreateNoWindow = false,
WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory
};
Run Code Online (Sandbox Code Playgroud)
但在独立的应用程序中,文件名应该是FileName = "myapp.exe"和Arguments = argsString。但是,该属性typeof(Program).Assembly.Location仍然返回myapp.dll,因为它是与独立应用程序打包的myapp.exe分布式副本的包装器,并且它调用相同的.dotnetmyapp.dll
在不知道我从哪里运行的情况下,我每次发布应用程序时都需要更改参数,这会显着减慢开发速度并使构建自动化变得更加困难。 …
通过使用,可以很容易地f:Func<'T, 'T>从F#调用'T -> 'Tf.Invoke
但是我该如何f:Func<'T, 'T, 'T>从F#打电话'T -> 'T -> 'T?
当我使用时,f.Invoke我得到了'T * 'T -> 'T,即一个元组而不是两个参数.
一位同事审查了我的代码并询问我为什么使用以下模式:
type MyType() =
member this.TestMethod() =
let a = 1
// do some work
let a = 2 // another value of a from the work result
()
Run Code Online (Sandbox Code Playgroud)
我告诉他这是一个糟糕的模式,我的意图是使用let mutable a = ....但后来他问为什么在F#类中有可能有这样的顺序绑定,而在模块或.fsx文件中是不可能的?实际上,我们正在改变一个不可变的值!
我回答说,在模块或.fsx文件中,let绑定变为静态方法,因此具有相同名称的绑定与具有相同名称的两个类属性相同的方式冲突是直截了当的.但我不知道为什么在方法中这是可能的!
在C#中,我发现对范围变量很有用,特别是在单元测试中,当我想通过复制粘贴代码来为测试用例组成一些不同的值时:
{
var a = 1;
Assert.IsTrue(a < 2);
}
{
var a = 42;
Assert.AreEqual(42, a);
}
Run Code Online (Sandbox Code Playgroud)
在F#中,我们不仅可以重复相同的let绑定,而且可以将一个不可变的绑定更改为可变的绑定,然后以通常的方式将其更改为:
type MyType() =
member this.TestMethod() =
let a = 1
// do some work
let a = 2 // another value of …Run Code Online (Sandbox Code Playgroud) 这是一个详细的答案,关于C#编译器foreach在IEnumerator<T>可变结构的情况下如何优化.
F#编译器是否执行相同的优化?
在F#中,我们为设计时类型安全提供了几个非常好的解决方案:类型别名和单例结构联合(并且没有隐式转换开始!):
// type aliases are erased at compile time
type Offset = int64<offset>
// no allocations
[<Struct>]
type Offset = Offset of int64
Run Code Online (Sandbox Code Playgroud)
什么是C#的替代品?
我从未见过标记结构的实际用法(包含单个元素),但看起来如果我们添加显式类型转换,那么我们可以获得与F#中的类型别名非常相似的设计时行为.那就是 - IDE会抱怨类型不匹配,并且必须明确地转换值.
以下是一些POC代码:
public struct Offset {
private readonly long _value;
private Offset(long value) {
_value = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Offset(long value) {
return new Offset(value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator long(Offset offset) {
return offset._value;
}
}
public interface IIndex<T> {
Offset OffsetOf(T value);
T AtOffset(Offset offset); …Run Code Online (Sandbox Code Playgroud) 我需要一个可以接受任意数量参数的函数,每个参数可以是类型'T或seq<'T>.在函数内部,我需要将它作为单个处理seq<'T>,所有输入以与它们提供的顺序相同的顺序组合.
显而易见的方法是:
module Test =
let flatten ([<ParamArray>] args) =
let flat = seq {
for a in args do
match box a with
| :? int as x -> yield x
| :? seq<int> as sq ->
for s in sq do
yield s
| _ -> failwith "wrong input type"
}
flat // this should be seq<int>
Run Code Online (Sandbox Code Playgroud)
但即使是最简单的情况,我也无法让它在FSI中发挥作用
let fl = Test.flatten 1;;
----------------------^
...: error FS0001: The type 'int' is not …Run Code Online (Sandbox Code Playgroud) 在这个答案和这个GitHub问题(顶部项目)中,有一个foreachC#编译器使用的优化描述.
基本上,IEnumerable<T>生成的代码调用GetEnumerator()然后MoveNext()在返回的对象上,而不是分配,总是使用直接call,因此避免装箱和虚拟调用.
是否可以用中间语言编写相同的逻辑?我是IL的初学者,但熟悉Unsafe包及其工作方式.我想知道是否有可能在IL中编写一个不安全的方法来接受一些对象并直接调用它的方法和属性?
(另外,有人可以提供一个链接到Roslyn仓库中的线路,这个foreach优化发生了吗?回购是如此之大和复杂,我到目前为止失去了.)
更新:
这是一个方法模板
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[ILSub(@"
.. IL code here to be replaced by ilasm.exe
.. Is there a way to do the same without boxing and virtual calls?
")]
public T CallIEnumerableMoveNextViaIL<T>(IEnumerable<T> enumerable)
{
// I know that the `enumerable` returns an enumerator that is a struct, but its type could be custom
// Next …Run Code Online (Sandbox Code Playgroud) 如果我使用二进制写入器将 C# 十进制数组保存到二进制 blob,我是否能够在 Java、Python 或 R 中无缝读取这个 blob?这些语言是否具有相应的数据类型,或者是否存在 .NET 十进制遵循的跨平台标准?
我在存储之前将所有数字数据转换为小数,因为当一个小数数组被差分然后压缩时,实际数据的结果 blob 大小比任何算法压缩的浮点 blob 小得多(我的测试显示 c.2x更小的空间)。并且小数不会失去差异的精度。但我不确定我是否可以从 .NET 语言以外的任何其他语言读取这些 blob。
我正在阅读维基页面,但我自己无法回答这个简单的问题。
更新:
目前我对decimal[]数组进行了不安全的引用并将其强制转换为(byte* )指针,但这等效于二进制编写器。问题是关于跨平台十进制互操作,而不是序列化。请参阅我在第一个答案中的评论。
我有一个内部泛型方法byte[] catchAllOperation<T>(T genericItem)和另一个byte[] arrayOperation<T>(T[] genericArray).另外,我有一个高度专业化的操作byte[] specializedOperation<TKey,TValue>(CustomMap<Tkey,TValue> customMap).
怎么写这样的方法?(伪):
public byte[] universalOperation<T>(T anything){
if(T is CustomMap<UKey,UValue>){ // UKey/UValue are unknown
return specializedOperation<UKey,UValue>(anything);
} else if(T is U[]){ // U is unknown
return arrayOperation<U>(anything);
}else{
return catchAllOperation<T>(anything);
}
}
Run Code Online (Sandbox Code Playgroud)
如何获得U以及如何调用arrayOperation<U>(anything);带有U如果我有只T(与同为CustomMap<>)?我所看到的大多数问题都假设U已经知道了.序列化程序使用反射为每个具体类型构造单独的方法,然后缓存该方法.但是在这里我只想在我能够检测到这些情况时,将通用方法重定向/发送到特殊情况.
我将有更多类似的类型CustomMap,因此有时间对代码/方法进行任何根本性的更改.所有特殊方法都利用了这样一个事实:对于blittable底层类型,一些转换和自定义布局显着提高了自定义类型的压缩率.对于自定义类型,我可以实现一个接口,但对于通用数组,它不是一个选项.
我正在学习不安全的 Rust,并尝试创建一个由指向某些不安全内存的指针支持的原子(例如来自 C 的缓冲区或内存映射文件)。
我试过这个:
use std::sync::atomic::{AtomicI64, Ordering};
fn main() -> () {
let mut v = vec![1i64, 2i64];
let ptr = &mut v[0] as *mut i64;
unsafe {
let a = std::mem::transmute::<*mut i64, AtomicI64>(ptr);
println!("{}", a.load(Ordering::Relaxed));
}
}
Run Code Online (Sandbox Code Playgroud)
但它打印的是指针的地址(例如2119547391296)而不是1。
创建位于某些外部缓冲区中的原子的正确方法是什么?
我想要相同的功能,例如 C# Interlocked.CompareExchange(ref *(long*)ptr, ...),所以也许还有其他方法可以在 Rust 中获取无锁同步原语?
更新:
看起来我需要std::intrinsics::{*},但它们在稳定的 Rust 中不可用。
更新2:
这会编译并打印1 2 2(即通过指针转换创建然后通过取消引用v[0]按预期更新)。但这是正确的吗?AtomicI64AtomicI64& *ptr
use std::sync::atomic::{AtomicI64, Ordering};
fn main() -> () {
let …Run Code Online (Sandbox Code Playgroud)