我有一个通用的Converter类
public class Converter
{
public static TargetType[] Convert<SourceType, TargetType>(SourceType[] data)
where SourceType : struct
where TargetType : struct
{
int N = data.Length;
TargetType[] result = new TargetType[N];
for (int i = 0; i < N; i++)
{
// We does this not work, what can I do else
result[i] = (TargetType)data[i];
}
return result;
}
}
问题1:为什么不能进行演员表演?我还能做什么? Convert.ChangeType要慢。
由于性能较差,我决定在不安全的代码中执行此操作。不幸的是,它不可能创建指向泛型的指针 - 因为它是众所周知的。出于这个原因,我创建了一个转换器,它在运行时决定类型并使用大量if来执行转换。
没有人提出任何问题。我可以创建一个通用的Convert例程并以某种方式对其进行特殊处理,在某些情况下我已经定义了数据类型。我目前不知道怎么做,但也许我看了你得到线索的例子:
public static double[] Convert<double, int>(int[] data)
{
int N = data.Length;
double[] result = new double[N];
unsafe
{
fixed (int* data_pinned = data)
fixed (double* out_pinned = result)
{
int* A = data_pinned;
double* B = out_pinned;
for (int i = 0; i < N; i++, A++, B++)
{
*B = ((double)*A);
}
}
}
return result;
}
下面你可以找到一个“小”的演示项目,它显示了不同演员的表现值:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace ConsoleApplication1
{
public static class CastTest
{
public static unsafe double[] Cast1(int[] input)
{
int N = input.Length;
double[] output = new double[N];
for (int i = 0; i < N; i++) output[i] = (double)(input[i]);
return output;
}
public static unsafe double[] Cast2(int[] input)
{
int N = input.Length;
double[] output = new double[N];
fixed (double* output_pinned = output)
{
double* outp = output_pinned;
fixed (int* input_pinned = input)
{
int* inp = input_pinned;
for (int i = 0; i < N; i++, inp++, outp++) *outp = (double)(*inp);
}
return output;
}
}
public static unsafe double[] Cast3(int[] input)
{
int N = input.Length;
double[] output = new double[N];
fixed (double* output_pinned = output)
{
double* outp = output_pinned;
fixed (int* input_pinned = input)
{
int* inp = input_pinned;
for (int i = 0; i < N; i++) outp[i] = (double)(inp[i]);
}
return output;
}
}
public static unsafe double[] Cast4(int[] input)
{
int N = input.Length;
double[] output = new double[N];
fixed (double* output_pinned = output)
{
fixed (int* input_pinned = input)
{
for (int i = 0; i < N; i++) output_pinned[i] = (double)(input_pinned[i]);
}
}
return output;
}
public static unsafe double[] Cast5(int[] input)
{
double[] output = new double[input.Length];
for (int i = 0; i < input.Length; i++) output[i] = (input[i]);
return output;
}
public static unsafe double[] Cast6(int[] input)
{
Converter<int, double> converter = (A) =>
{
return A;
};
return Array.ConvertAll<int, double>(input, converter);
}
public static void StartTest()
{
int[] A = new int[100000];
int N = 10000;
var w1 = Stopwatch.StartNew();
for (int i = 0; i < N; i++) { double[] A1 = Cast1(A); }
w1.Stop();
Console.WriteLine(String.Format("{0}: {1}ms", 1, w1.ElapsedMilliseconds));
var w2 = Stopwatch.StartNew();
for (int i = 0; i < N; i++) { double[] A2 = Cast2(A); }
w2.Stop();
Console.WriteLine(String.Format("{0}: {1}ms", 2, w2.ElapsedMilliseconds ));
var w3 = Stopwatch.StartNew();
for (int i = 0; i < N; i++) { double[] A3 = Cast3(A); }
w3.Stop();
Console.WriteLine(String.Format("{0}: {1}ms", 3, w3.ElapsedMilliseconds));
var w4 = Stopwatch.StartNew();
for (int i = 0; i < N; i++) { double[] A4 = Cast4(A); }
w4.Stop();
Console.WriteLine(String.Format("{0}: {1}ms", 4, w4.ElapsedMilliseconds));
var w5 = Stopwatch.StartNew();
for (int i = 0; i < N; i++) { double[] A5 = Cast5(A); }
w5.Stop();
Console.WriteLine(String.Format("{0}: {1}ms", 5, w5.ElapsedMilliseconds));
var w6 = Stopwatch.StartNew();
for (int i = 0; i < N; i++) { double[] A6 = Cast6(A); }
w6.Stop();
Console.WriteLine(String.Format("{0}: {1}ms", 6, w6.ElapsedMilliseconds));
}
}
}
非常感谢任何帮助以提高性能。 数组大小和重复的大小对我来说都是实际值。实际上,出于测试目的,这些值也比通常使用的值略低。
有可能这样做吗?
由于 马丁
答案 0 :(得分:2)
无法进行演员表,因为无法保证 在所涉及的两种类型之间进行转换。如果SourceType
为Guid
而TargetType
为double
,该怎么办?编译器基本上不能发出转换。
最简单的方法可能是提供代表:
public static TTarget[] Convert<TSource, TTarget>(TSource[] data,
Func<TSource, TTarget> conversion)
{
TargetType[] result = new TargetType[data.Length];
for (int i = 0; i < data.Length; i++)
{
result[i] = conversion(data[i]);
}
return result;
}
当然这与调用Array.ConvertAll
基本相同......那不能做你想要的吗?
是的,经常调用转换会产生很小的性能开销 - 但是你是否证明了自己的性能开销是个问题?我至少尝试使用Array.ConvertAll
作为第一次尝试。