문제

하고 싶을 얻 byte[]float[] 가능한 한 빨리 없이,반복을 통해 전체 배열(을 통해 캐스트 아마).안전하지 않은 코드는 괜찮습니다.감사합니다!

내가 찾는 것은 바이트 배열은 4 시간 이상 float array(차원의 바이트 배열 될 것이다 4 배로 부유물의 배열을,이후 각 부유물로 구성된 4 개의 바이트).내가 이것을 BinaryWriter.

편집:하는 그 비판 screaming"조화":나는 벤치마킹 사용하여 이미 프로파일하기 전에 나는 최적화되어 있습니다.이 있었다 중요한 속도가 증가하기 때문에 파일에 쓰기을 통해 캐시 및 플로트 배열이 정확하게 크기가 일치하는 부문에 디스크가 있습니다.이진 작가 랩 파일 핸들로 만든 pinvoke'd win32API 를 사용합니다.최적화가 발생하기 때문이 줄어듭니다 수의 함수 호출합니다.

과과 관련하여,메모리,이 응용 프로그램을 만들 대규모 캐시를 사용하는 메모리를 많.나는 할당할 수 있는 바이트 버퍼를 한 번 다시 사용하여 그것은 많은 시간--이중에서 메모리 사용량이 특히 인스턴스는 금액을 반올림 오류가에서 전반적으로 메모리를 소비합니다.

그래서 나는 여기에서 학습하지 않게 조정;)

도움이 되었습니까?

해결책

변환이 발생하지 않으려면 buffer.blockcopy ()를 제안합니다.

public static void BlockCopy(
    Array src,
    int srcOffset,
    Array dst,
    int dstOffset,
    int count
)

예를 들어:

float[] floatArray = new float[1000];
byte[] byteArray = new byte[floatArray.Length * 4];

Buffer.BlockCopy(floatArray, 0, byteArray, 0, byteArray.Length);

다른 팁

더러운 빠른 것이 있습니다 (안전하지 않은 코드가 아님) 이것을하는 방법 :

[StructLayout(LayoutKind.Explicit)]
struct BytetoDoubleConverter
{
    [FieldOffset(0)]
    public Byte[] Bytes;

    [FieldOffset(0)]
    public Double[] Doubles;
}
//...
static Double Sum(byte[] data)
{
    BytetoDoubleConverter convert = new BytetoDoubleConverter { Bytes = data };
    Double result = 0;
    for (int i = 0; i < convert.Doubles.Length / sizeof(Double); i++)
    {
        result += convert.Doubles[i];
    }
    return result;
}

이것은 효과가 있지만 지원을 확신하지 못합니다. 단핵증 또는 최신 버전의 CLR. 유일한 이상한 점은 array.Length 바이트 길이입니다. 이것은 배열에 저장된 배열 길이를 보고이 배열이 바이트 배열이기 때문에 길이가 여전히 바이트 길이에 있기 때문에 설명 할 수 있습니다. 인덱서는 이중 8 바이트가 큰 것으로 생각하므로 계산이 필요하지 않습니다.

나는 그것을 좀 더 찾았고 실제로 설명되어 있습니다. MSDN, 방법 : 속성을 사용하여 C/C ++ Union을 만듭니다 (C# 및 Visual Basic), 이것이 향후 버전에서 지원 될 가능성이 있습니다. 그래도 모노에 대해 잘 모르겠습니다.

조기 최적화는 모든 악의 근원입니다! 각 플로트를 반복하려는 @Vlad의 제안은 바이트 []로 전환하는 것보다 훨씬 합리적인 답변입니다. 요소의 수가 증가하기 위해 다음 런타임 테이블을 사용하십시오 (평균 50 런) :

Elements      BinaryWriter(float)      BinaryWriter(byte[])
-----------------------------------------------------------
10               8.72ms                    8.76ms
100              8.94ms                    8.82ms
1000            10.32ms                    9.06ms
10000           32.56ms                   10.34ms
100000         213.28ms                  739.90ms
1000000       1955.92ms                10668.56ms

적은 수의 요소에 대해서는 둘 사이에 차이가 거의 없습니다. 수많은 요소 범위에 들어가면 float []에서 Byte []까지 복사하는 데 소요되는 시간이 이점보다 훨씬 큽니다.

그러니 간단한 것을 가지고 가십시오.

float[] data = new float[...];
foreach(float value in data)
{
    writer.Write(value);
}

메모리 복사 및 반복을 피하는 방법이 있습니다.

정말 못생긴 해킹을 사용하여 (안전하지 않은) 메모리 조작을 사용하여 배열을 다른 유형으로 임시로 변경할 수 있습니다.

32 & 64 비트 OS 에서이 해킹을 테스트 했으므로 휴대용이어야합니다.

소스 + 샘플 사용량이 유지됩니다 https://gist.github.com/1050703 , 그러나 당신의 편의를 위해서도 여기에 붙여 넣을 것입니다.

public static unsafe class FastArraySerializer
{
    [StructLayout(LayoutKind.Explicit)]
    private struct Union
    {
        [FieldOffset(0)] public byte[] bytes;
        [FieldOffset(0)] public float[] floats;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    private struct ArrayHeader
    {
        public UIntPtr type;
        public UIntPtr length;
    }

    private static readonly UIntPtr BYTE_ARRAY_TYPE;
    private static readonly UIntPtr FLOAT_ARRAY_TYPE;

    static FastArraySerializer()
    {
        fixed (void* pBytes = new byte[1])
        fixed (void* pFloats = new float[1])
        {
            BYTE_ARRAY_TYPE = getHeader(pBytes)->type;
            FLOAT_ARRAY_TYPE = getHeader(pFloats)->type;
        }
    }

    public static void AsByteArray(this float[] floats, Action<byte[]> action)
    {
        if (floats.handleNullOrEmptyArray(action)) 
            return;

        var union = new Union {floats = floats};
        union.floats.toByteArray();
        try
        {
            action(union.bytes);
        }
        finally
        {
            union.bytes.toFloatArray();
        }
    }

    public static void AsFloatArray(this byte[] bytes, Action<float[]> action)
    {
        if (bytes.handleNullOrEmptyArray(action)) 
            return;

        var union = new Union {bytes = bytes};
        union.bytes.toFloatArray();
        try
        {
            action(union.floats);
        }
        finally
        {
            union.floats.toByteArray();
        }
    }

    public static bool handleNullOrEmptyArray<TSrc,TDst>(this TSrc[] array, Action<TDst[]> action)
    {
        if (array == null)
        {
            action(null);
            return true;
        }

        if (array.Length == 0)
        {
            action(new TDst[0]);
            return true;
        }

        return false;
    }

    private static ArrayHeader* getHeader(void* pBytes)
    {
        return (ArrayHeader*)pBytes - 1;
    }

    private static void toFloatArray(this byte[] bytes)
    {
        fixed (void* pArray = bytes)
        {
            var pHeader = getHeader(pArray);

            pHeader->type = FLOAT_ARRAY_TYPE;
            pHeader->length = (UIntPtr)(bytes.Length / sizeof(float));
        }
    }

    private static void toByteArray(this float[] floats)
    {
        fixed(void* pArray = floats)
        {
            var pHeader = getHeader(pArray);

            pHeader->type = BYTE_ARRAY_TYPE;
            pHeader->length = (UIntPtr)(floats.Length * sizeof(float));
        }
    }
}

그리고 사용법은 다음과 같습니다.

var floats = new float[] {0, 1, 0, 1};
floats.AsByteArray(bytes =>
{
    foreach (var b in bytes)
    {
        Console.WriteLine(b);
    }
});

당신은 바이너리 라이터를 더 잘하는 것이 좋습니다 당신을 위해 이것을하십시오. 사용하는 방법에 관계없이 전체 데이터 세트에 반복 될 것이므로 바이트를 사용하는 데 아무런 의미가 없습니다.

지만 당신을 얻을 수 있습니다 byte* 포인터를 사용하여 unsafefixed, 변환할 수 없습 byte* 하기 byte[] 기 위해서 작가가 그것을 받아들이지 않고 매개 변수로 수행하는 데이터의 복사본입니다.는 당신을 원하지 않을 것 같은 두 번의 메모리 공간 추가 반복을 통해 불가피한 반복해야 하는 수행하기 위해 데이터를 출력하여 디스크에 있습니다.

대신에,당신은 여전히 나 반복의 배열은 수레와 각 쓰기 float 해 작가 개별적으로, 를 사용하여, Write(double) 방법입니다.그것은 여전히 빠르기 때문에 완충의 내부에 작가입니다.보 sixlettervariables's 숫자입니다.

우리는 ludicrousspeedserialization이라는 수업이 있으며 다음과 같은 안전하지 않은 방법이 포함되어 있습니다.

    static public byte[] ConvertFloatsToBytes(float[] data)
    {
        int n = data.Length;
        byte[] ret = new byte[n * sizeof(float)];
        if (n == 0) return ret;

        unsafe
        {
            fixed (byte* pByteArray = &ret[0])
            {
                float* pFloatArray = (float*)pByteArray;
                for (int i = 0; i < n; i++)
                {
                    pFloatArray[i] = data[i];
                }
            }
        }

        return ret;
    }

기본적으로 무대 뒤에서 루프를 위해 사용하지만 한 줄로 작업을 수행합니다.

byte[] byteArray = floatArray.Select(
                    f=>System.BitConverter.GetBytes(f)).Aggregate(
                    (bytes, f) => {List<byte> temp = bytes.ToList(); temp.AddRange(f); return temp.ToArray(); });
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top