.net 환경 에서 크로스 프로 세 스,고주파 읽 기와 쓰기 데이터 에 대한 문제

1.수요 배경
1.최근 프로젝트 는 고주파 로 데 이 터 를 읽 고 쓰 도록 요구 하고 데이터 의 양도 크 지 않 으 며 다 중 표 는 모두 백만 개의 상하 에 있 습 니 다.
표 가 가장 큰 것 도 25 만 정도 인 데 역사 데이터 표 는 언급 되 지 않 기 때문에 고려 할 필요 가 없다.
어 려 운 점 은 이 규모 의 핫 이 슈 데이터 로 변화 가 매우 빈번 하 다 는 점 이다.
데 이 터 는 일부 검 측 장치 의 수집 데이터 에서 기원 되 고 일부 큰 표 는 짧 은 시간 안에(예 를 들 어 몇 초)대부분 변화 할 수 있 습 니 다.
또한 메 인 프로그램 도 일부 백 스테이지 서 비 스 는 계속 문의 하고 특정한 유형의 장 치 를 읽 고 써 야 하기 때문에 정보 교환 시간 이 가능 한 한 짧 아야 한다.
2.이전의 해결 방안 은 모든 핫 이 슈 데 이 터 를 공유 메모리 에 통일 적 으로 불 러 오고 지탱 할 수 있 는(밀리초 단위)까지 불 러 오 는 것 이 었 으 나 시스템 구조 업그레이드 로 인해 이전의 프로그램(20 년 전의)은 호 환 되 지 않 았 습 니 다.
하나만 다시 쓸 수 있 습 니 다.가장 먼저 생각 나 는 것 은 redis 입 니 다.그 당시 에 모든 API 를 다시 쓴 후에 테스트 를 통 해 효율 이 안 되 는 것 을 발 견 했 습 니 다.네,잘못 보지 않 았 습 니 다.redis 도 사용 범위 가 있 습 니 다.
3.redis 읽 기와 쓰기 가 매우 빠 르 지만 대량의 읽 기와 쓰기 작업 에 대해 저 는 지원 이 부족 하 다 고 생각 합 니 다.redis 는 대량 읽 기와 쓰 기 를 지원 하지만 효율 이 빠 르 지 않 습 니 다.
문자열(string)형식의 대량 읽 기와 쓰기 에 대해 테스트 한 적 이 있 습 니 다.효율 이 비교적 좋 은 것 은 매번 200~250 개 사이 에 20 만 개의 데 이 터 를 처리 하 는 데 5 초 정도 걸린다.(PC 기기,8G,4 핵)
그리고 질서 있 는 집합(sorted set)유형 에 대해 대량으로 쓰 는 작업 은 매우 어색 하고 API 를 수정 하지 않 았 습 니 다.(다른 방식 이 있 으 면 가르쳐 주 십시오)저 는 테스트 한 적 이 있 습 니 다.효율 은 string 형식 만큼 높 지 않 습 니 다.
다른 유형 은 나의 업무 장면 에 적합 하지 않 아서 사용 할 생각 을 하지 않 았 다.
4.그래서 프로젝트 팀 은 마지막 으로 공유 메모리 로 사용 하기 로 결 정 했 습 니 다.먼저.net 환경 에서 c\#공유 메모 리 를 사용 하기 로 결 정 했 습 니 다.이 기능 은 사용 할 수 있 는 사람 이 많 지 않 습 니 다.사실은.net 4.0 버 전에 이미 통합 되 었 습 니 다.
System.IO.Memory Mapped File 네 임 스페이스 에서이 라 이브 러 리 는 어 이 없 게 한다.안에 쓸 수 있 는 것 은 Write,read 두 가지 방법 뿐 이 고 바이트 에 대한 조작 이기 때문이다.
아주 많은 타 입 전환 이 필요 합 니 다.귀 찮 습 니 다!바이트 단위 로 백만 급 데 이 터 를 저장 해 야 하 는 메모리 데이터 베 이 스 를 구축 하 는 것 이 얼마나 번 거 로 운 지 생각해 보 세 요.
색인 기능 을 수 동 으로 해결 해 야 합 니 다.각종 조 회 를 지원 해 야 하기 때문에 마지막 으로 하루 동안 DEMO 를 썼 습 니 다.마지막 으로 테스트 한 결과 효율 이 크게 향상 되 지 않 았 습 니 다.그 당시 에 상호 배척 테스트 를 추 가 했 기 때 문 입 니 다.
하지만 밀리초 급 차 는 멀다.이 기술 에 관심 이 있 는 것 은 정원 에 있다 는 것 을 알 수 있다.예 를 들 어:https://www.cnblogs.com/zeroone/archive/2012/04/18/2454776.html
2.맞아요.1 절 은 너무 많이 썼어 요.
1.마지막 으로 분석 하면 이것 은 c\#언어의 병목 이 어야 한다.c\#이런 소란 조작 에 대해 그리 성숙 하지 않다.
2.마지막 으로 겨냥 하여 VC 를 사용 하여 dll 을 개발 하고 그 안에 메모리 데이터 에 대한 읽 기와 쓰기 기능 을 패키지 한 다음 c\#호출 하기 로 결정 합 니 다.
3.본인 의 C,C++가 그리 익숙 하지 않 고 사례 를 참고 했다.예 를 들 어 정원 안의:http://www.cnblogs.com/cwbcwb505/archive/2008/12/08/1350505.html
4.네,잘못 보지 않 았 습 니 다.2008 년 에 저 는 더 빠 른 것 을 보 았 습 니 다.보아하니 바 텀 개발 C,C++가 그렇게 오래 지속 되 고 쇠퇴 하지 않 는 것 은 이치 에 맞지 않 는 것 이 아니 라 많은 기술 이 지금 사용 되 고 있 는 것 같 습 니 다.
5.공유 메모리 가 무엇 인지 봅 시다.

3.코드 쓰기 시 작 했 어 요.
1.먼저 2 개의 콘 솔 프로젝트 를 구축 하고 MFC 를 지원 합 니 다.
2.먼저 이렇게:공유 메모 리 를 만 들 고 데 이 터 를 초기 화 합 니 다.
3.다시 이렇게:읽 기와 쓰기 데이터 테스트,마지막 수정
4.마지막 으로 그림 의 디 테 일 을 수정 하고 테스트 하 며 효 과 를 봅 니 다.


5.완 성 했 습 니 다.see,쉽 지 않 나 요?다 알 아 요?

4.정말 코드 를 붙 여 야 겠 어 요.
1.매 거 진 반환 상 태 를 정의 합 니 다.

typedef enum
{
    Success = 0,
    AlreadyExists = 1,
    Error = 2,
    OverSize = 3
}enumMemory;
2.테스트 에 사용 할 구조 체 를 다시 정의 합 니 다.

typedef struct
{
    int        TagID;
    char    TagName[32];
    int        Area;
    double    EngVal;
    double    UpdateTime;
    double    RawMax;
    double    RawMin;
    double    RawVal;
    char    Name[50];
    char    Al;
    double    ASTime;
    char    MaskState;
    double    AMTime;
    char    Cf;
    char    Tdf;
    char    AlarmCode[32];
}TENG;
3.공유 메모리 생 성 시작

int Create(UINT size)
    {
        // Data
        HANDLE fileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, “Name”);

        if (fileMap == NULL || fileMap == INVALID_HANDLE_VALUE)
            return Error;

        if (GetLastError() == ERROR_ALREADY_EXISTS)
            return AlreadyExists;

        // init
        void *mapView = MapViewOfFile(fileMap, FILE_MAP_WRITE, 0, 0, size);

        if (mapView == NULL)
            return Error;
        else
            memset(mapView, 0, size);

        return Success;
    }
4.다시 데 이 터 를 쓰기 시작 합 니 다.

int Write(void *pDate, UINT nSize, UINT offset)
    {
        // open
        HANDLE fileMap = OpenFileMapping(FILE_MAP_WRITE, FALSE, “Name”);

        if (fileMap == NULL)
            return Error;

        // hander
        void *mapView = MapViewOfFile(fileMap, FILE_MAP_WRITE, 0, 0, nSize);

        if (mapView == NULL)
            return Error;
        else
            WriteDataPtr = mapView;

        // write
        memcpy(mapView, pDate, nSize);

        UnmapViewOfFile(pMapView);
        return Success;
    }
5.데이터 읽 기 시작

int Read(void *pData, UINT nSize, UINT offset)
    {
        // open
        HANDLE fileMap = OpenFileMapping(FILE_MAP_READ, FALSE, GetTableName());

        if (fileMap == NULL)
            return Error;

        // hander
        void *pMapView = MapViewOfFile(fileMap, FILE_MAP_READ, 0, 0, nSize);

        if (pMapView == NULL)
            return Error;
        else
            ReadDataPtr = pMapView;

        memcpy(pData, (pMapView, nSize);

        UnmapViewOfFile(pMapView);
        return Success;
    }
6.OK,복잡 하지 않 습 니 다.인터넷 에 이런 자료 가 있 습 니 다.마지막 으로 우 리 는 테스트 프로그램 을 붙 입 니 다.

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int length = 100000;
    CEng * ceng = new CEng();
    DWORD dwStart = GetTickCount();

    for (int i = 0; i < length; i++) {
        TENG eng;
        ceng->Read(&eng, ceng->size, ceng->size * i);

        eng.EngVal = i;
        ceng->Write(&eng, ceng->size, (i*ceng->size));

        if (i % 10000 == 0 || i == length - 1)
            printf("     Eng.TagName:%s 
", eng.TagName); } printf(" %d, :%d
", length, GetTickCount() - dwStart); // TENG eng5000; ceng->Read(&eng5000, ceng->size, ceng->size * 5000); printf("

"); printf(" 5000 Eng TagID:%d, EngVal:%lf
", eng5000.TagID, eng5000.EngVal); scanf_s(" "); return 0; }
7.테스트 프로그램 도 작성

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int length = 100000;
    CEng * ceng = new CEng();
    ceng->Create(ceng->size * length);

    DWORD dwStart = GetTickCount();

    for (int i = 0; i < length; i++)
    {
        TENG eng;
        memset(&eng, 0, ceng->size);

        eng.TagID = i;
        sprintf_s(eng.AlarmCode, "AlarmCode.%d", i);
        sprintf_s(eng.TagName, "TagName.%d", i);

        if (i % 10000 == 0 || i == length - 1)
            printf("     Eng.TagName:%s 
", eng.TagName); ceng->Write(&eng, ceng->size, (i*ceng->size)); } // print time printf(" , :%d
", length); printf(" :%d
", GetTickCount() - dwStart); scanf_s(" "); return 0; }
8、다시 붙 여야 지


5.DLL 만 드 는 걸 깜빡 할 뻔 했 어 요.
1.외부 함수 정의

extern "C" __declspec(dllexport) int ReadFromSharedMemory(TENG *pData, int nSize, int offset)
{
    return ceng->Read(pData, nSize, offset);
}

extern "C" __declspec(dllexport) int WriteToSharedMemory(void *pData, int nSize, int offset)
{
    return ceng->Write(pData, nSize, offset);
}
2.자,VC 는 여기까지 입 니 다.도시락 을 받 으 러 가도 됩 니 다.c\#입장

public class Lib
    {
        [DllImport("ConsoleApplication4.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int ReadFromSharedMemory(IntPtr pData, int nSize, int offset);

        [DllImport("ConsoleApplication4.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int WriteToSharedMemory(IntPtr pData, int nSize, int offset);
    }
3,c\#테스트

static void Main(string[] args)
        {
            var length = 100000;
            var startTime = DateTime.Now;
            var size = Marshal.SizeOf(typeof(TEng));
            var intPtrOut = Marshal.AllocHGlobal(size);
            var intPtrIn = Marshal.AllocHGlobal(size);

            for (var i = 0; i < length; i++)
            {
                Lib.ReadFromSharedMemory(intPtrOut, size, size * i);

                var eng = Marshal.PtrToStructure<TEng>(intPtrOut);
                eng.EngVal = i;

                Marshal.StructureToPtr(eng, intPtrIn, true);
                Lib.WriteToSharedMemory(intPtrIn, size, size * i);

                if (i % 10000 == 0)
                    Console.WriteLine("eng.TagID:{0}", eng.TagID);
            }

            Console.WriteLine("   {0},  :{1}   ", length.ToString(),
                (DateTime.Now - startTime).TotalMilliseconds.ToString());

            //     
            var intPtr100 = Marshal.AllocHGlobal(size);
            Lib.ReadFromSharedMemory(intPtr100, size, size * 100);

            var eng100 = Marshal.PtrToStructure<TEng>(intPtr100);

            Console.WriteLine();
            Console.WriteLine("    ");
            Console.WriteLine(" 100 Eng TagID:{0},EngVal:{1}", eng100.TagID, eng100.EngVal);

            Console.ReadKey();
        }

4.165 밀리초 로 VC 에서 운행 하 는 것 에 비해 수량 급 이 부족 하지만 괜 찮 습 니 다.
c\#환경 에서 끊 임 없 는 Marshal.PtrToStructure,Marshal.structureToPtr 가 필요 하기 때문에 데 이 터 를 위탁 관리 메모리 유 공유 메모리 사이 로 자주 옮 깁 니 다.
시간 이 필요 합 니 다.더 좋 은 처리 방법 이 있 습 니 다.가르쳐 주세요.
6.크로스 스 레 드,프로 세 스 때문에 상호 배척 량 을 고려 해 야 합 니 다.
1.아주 간단 합 니 다.MFC 에 기 존의 CMutex 가 있 는데 Write 에 넣 어서 효율 을 봅 니 다.

상호 배척 량 은 자원 을 소모 해 야 하 며,100 밀리초 가 더 들 어 갈 것 이다.
2.읽 기와 쓰기 에 서로 배척 하 는 양 을 더 해 보 자.

80 여 밀리초 가 더 많아 졌 습 니 다.
물고기 와 곰 발바닥 을 동시에 가 질 수 는 없 잖 아.실제 운용 장면 에 근거 하여 상호 반 론 량 을 더 해 야 한다 고 생각해 야 한다.
자,사람들 이 51 번 놀 러 갔 는데 저 는 집에 서 프로그램 을 만 들 었 습 니 다.이 를 통 해 제 취미 가 높 은 것 을 알 수 있 습 니 다.목욕,빨래,그리고 밥 을 먹 으 러 갔 고 하루 종일 음식 을 먹 지 않 았 습 니 다.
이상 은.net 환경 에서 크로스 프로 세 스,고주파 읽 기 쓰기 데이터 에 대한 상세 한 내용 입 니 다.더 많은.net 크로스 프로 세 스 고주파 읽 기 쓰기 데이터 에 관 한 자 료 는 우리 의 다른 관련 글 에 관심 을 가 져 주 십시오!

좋은 웹페이지 즐겨찾기