Study/TIL(Today I Learned)

24.07.31 C#

에린_1 2024. 7. 31. 19:49
728x90

C#

Environment.ProcessorCount

  • C#에서 현재 시스템의 논리 프로세서(코어) 수를 반환하는 속성이다.
  • 이 속성은 .NET의 System 네임스페이스에 포함되어 있으며, 멀티 스레딩 또는 병렬 작업을 최적화할 때 유용하게 사용할 수 있다.

논리 프로세서와 물리 프로세서

  • 논리 프로세서
    • 하이퍼스레딩 기술과 같은 기술을 통해 운영 체제가 인식하는 프로세서의 수를 나타낸다.
  • 물리 프로세서
    • 실제로 존재하는 코어의 수를 나타낸다.

활용

  • 스레드 풀 크기 결정
    • 시스템의 논리 프로세서 수를 기반으로 스레드 풀의 크기를 동적으로 결정할 수 있다.
  • 병렬 작업 최적화
    • 데이터 병렬 처리를 최적화할 때 사용할 스레드의 수를 조정할 수 있다.
  • 시스템 정보 제공
    • 애플리케이션에서 시스템의 프로세서 개수를 사용자에게 표시하거나 로그에 기록할 수 있다.

주의 사항

  • Environment.ProcessorCount는 논리 프로세서의 수를 반환하므로, 하이퍼 스레딩이 활성화된 시스템에서는 물리적 코어의 수보다 큰 값을 반환할 수 있다.
  • 프로세서의 수를 기반으로 작업을 분배할 때는 CPU 사용률, I/O 대기 시간 등을 고려하여 적절한 병렬 작업의 수준을 결정하는 것이 중요하다.

Static extern

  • 외부에서 구현된 정적 메서드를 선언하는 데 사용된다. 이 키워드 조합은 주로 플랫폼 호출을 통해 네이티브 코드(예: C/C++ 라이브러리의 함수)를 호출할 때 사용된다.
  • extern 키워드는 메서드의 구현이 외부에 있다는 것을 나타내며, static 키워드는 해당 메서드가 클래스의 인스턴스와 독립적임을 의미한다.
  • 보통 DLL(동적 링크 라이브러리)에 있는 함수를 호출하기 위해 사용된다. DllImport 속성을 사용하여 해당 함수가 포함된 DLL을 지정해야 한다.

중요 사항

  1. 플랫폼 호출(P/Invoke)
    • extern 키워드는 메서드의 구현이 관리되지 않는 코드(네이티브 코드) 에서 제공됨을 의미한다.
    • P/Invoke는 C# 코드에서 네이티브 DLL의 함수를 호출할 때 사용된다.
  2. 메서드의 반환값과 매개변수
    • 네이티브 함수의 반환값과 매개변수를 정확하게 일치시키는 것이 중요하다.
    • 잘못된 선언은 런타임 오류를 초래할 수 있다.
  3. 메모리 관리
    • 네이티브 코드와 상호 작용할 때는 메모리 관리에 주의해야 한다. 잘못된 포인터 사용 또는 메모리 해제는 충돌을 일으킬 수 있다.
  4. 플랫폼 종속성
    • P/Invoke는 주로 Windows 플랫폼에서 사용되며, 플랫폼 종속적인 코드가 될 수 있다. 다른 운영체제에서 사용할 때는 주의해야 한다.

MethodImpl

  • Methodlmpl 특성(attribute)은 .NET에서 메서드의 구현 방식이나 특정 기능을 지정하는 데 사용된다. 이 특성은 주로 성능 최적화, 동기화, 인라인(inline) 규칙 등을 제어하기 위해 사용된다.
  • MethodImplAttribute는 System.Runtime.CompilerServices 네임스페이스에 정의되어 있으며, 메서드, 생성자 또는 속성 접근자에 적용할 수 있다.

주요 MethodImplOptions 값

  • NoInlining
    • 메서드가 JIT(Just-In-Time) 컴파일러에 의해 인라인되지 않도록 한다. 인라인은 메서드 호출을 메서드 본문으로 대체하는 최적화 기술이다.
  • AggressiveInlining
    • JIT 컴파일러가 가능하면 메서드를 인라인하려고 시도하도록 한다. 이는 성능을 극대화하기 위해 사용될 수 있다.
  • Synchronized
    • 메서드에 대한 접근이 스레드 안전하게 보장된다. 해당 메서드가 호출될 때 자동으로 lock(this)와 같은 방식으로 동기화된다. 그러나 성능 저하와 교착 상태(deadlock)의 위험이 있으므로 일반적으로 권장되지 않는다.
  • InternalCall
    • 메서드 구현이 네이티브 코드에 있으며, 런타임에 의해 호출될 때 실행된다. 일반적으로 CLR의 내부 메서드에 사용된다.
  • ForwardRef
    • 메서드가 나중에 제공될 것임을 나타낸다. 메서드의 실제 구현은 제공되지 않으며, 주로 런타임이 이 기능을 사용할 수 있다.
  • PreserveSig
    • 메서드의 서명이 그대로 유지되도록 지정한다. COM 상호 운용 시, HRESULT 반환 값을 유지하기 위해 사용된다.

주의 사항

  • MethodImplOptions.Synchronized는 모든 메서드 호출에 대해 잠금을 설정하므로, 동시성 문제를 해결할 수 있지만 성능에 부정적인 영향을 미칠 수 있다. 가능하면 lock문을 사용하여 명시적인 잠금 관리가 더 바람직하다.
  • AggressiveInlining 및 NoInlining은 JIT 컴파일러에 대한 힌트일 뿐, 반드시 이러한 방식으로 컴파일되도록 보장하지는 않는다.

bool 함수<TEnum>(this TEnum, params TEnum[])

  1. 제네릭 타입 매개변수
    • <TEnum>은 제네릭 타입 매개변수이다. 이는 함수가 특정 타입에 대해 동작함을 나타낸다.
  2. 확장 메서드
    • this TEnum은 이 함수가 확장 메서드임을 나타낸다.
    • 이는 TEnum 타입의 객체에 대해 이 메서드를 직접 호출할 수 있게 해준다.
  3. 가변 길이 매개변수
    • params TEnum[]는 가변 길이 매개변수 배열이다.
    • 이 함수를 호출할 때 0개 이상의 TEnum 타입 인자를 전달할 수 있다.
  • params TEnum[] 를 통해 Enum 값들의 배열을 받을 수 있으며, 이는 리스트와 유사하게 동작할 수 있다.

확장 메서드(Extension Method)

  • 기존 타입에 새로운 메서드를 추가할 수 있게 해준다. 이는 원본 타입의 소스 코드를 수정하지 않고도 새로운 기능을 추가할 수 있는 강력한 방법이다.

기본 개념

  • 정적 클래스 내에 정의된다.
  • 첫 번째 매개변수에 this 키워드를 사용한다.
  • 이 첫 번째 매개변수는 확장하고자 하는 타입을 나타낸다.

문법

public static class ExtensionClass
{
    public static ReturnType MethodName(this ExtendedType variable, OtherParameters)
    {
        // 메서드 구현
    }
}

특징

  • 원본 타입을 수정하지 않고 새 기능을 추가할 수 있다.
  • 인스턴스 메서드처럼 호출할 수 있다.
  • 네임스페이스를 통해 확장 메서드의 가시성을 제어할 수 있다.

사용 사례

  • 기본 .NET 타입에 유틸리티 메서드 추가
  • 인터페이스에 기본 구현 제공
  • 제네릭 타입에 대한 확장 기능 구현

장점

  • 코드의 가독성과 유지보수성 향상
  • 기존 코드를 변경하지 않고 새 기능 추가 가능
  • 인터페이스에 대한 확장 가능

주의사항

  • 남용하면 코드가 복잡해질 수 있다.
  • 확장 메서드와 인스턴스 메서드 간의 이름 충돌에 주의해야 한다.
  • 확장 메서드는 정적 바인딩을 사용하므로 다형성을 지원하지 않는다.

제약사항

  • 확장 메서드는 static 클래스에서만 정의할 수 있다.
  • 확장 대상 타입의 private 멤버에는 접근할 수 없다.

Dictionary<TKey, TValue>

  • 고유한 키를 기반으로 값을 저장하는 컬렉션이다.

특징

  • 고유한 키
    • Dictionary에서 각 키는 고유해야 한다. 동일한 키를 여러 번 추가하려고 하면 ArgumentException 예외가 발생한다.
  • 값 덮어쓰기
    • 이미 존재하는 키에 대해 값을 설정하면, 해당 키의 기존 값이 새로운 값으로 대체된다.
    • 이는 myDictionary[1] = “Updated First”; 와 같은 방식으로 수행할 수 있다.
  • 예외 처리
    • Add 메서드를 사용하여 중복된 키를 추가하려고 하면 ArgumentException이 발생하므로, 이를 처리할 필요가 있다.
  • 확인 및 제거
    • 특정 키가 존재하는지 확인하려면 ContainsKey 메서드를 사용한다.
    • 키 - 값 쌍을 제거하려면 Remove 메서드를 사용한다.

Google.Protobuf IDeepClonealbe<T>

  • 프로토콜 버퍼스(Protocol Buffers, Protobuf) 메시지 객체를 깊은 복사(deep copy)하는 기능을 제공하는 인터페이스이다. 이는 Protobuf를 사용하여 정의된 메시지 타입에서 주로 사용된다.
  • Protobuf는 구글에서 개발한 언어 중립적인 데이터 직렬화 라이브러리이다.

사용 목적

  1. 깊은 복사
    • 깊은 복사는 객체의 복사본을 만들 때, 원래 객체의 모든 필드 값을 복사하고 그 필드들이 참조하는 객체들 역시 모두 복사하여, 원래 객체와 독립적인 새로운 객체를 만드는 작업을 말한다. 이는 얕은 복사(참조만 복사)와 대비된다.
  2. 불변성 유지
    • Protobuf 메시지 객체는 불변성을 유지하는 것이 일반적이다. 원본 객체의 상태를 변경하지 않고, 수정된 복사본을 생성하기 위해 깊은 복사가 필요할 수 있다.
  3. 데이터 변형 방지
    • 데이터를 복사하여 원본을 보호하고, 복사본을 사용하여 작업을 수행함으로써 데이터 변형을 방지한다.

주의사항

  • 성능
    • 깊은 복사는 원래 객체와 동일한 구조의 새로운 객체를 생성하므로, 큰 객체를 깊은 복사할 때는 성능에 주의해야 한다.
  • 복사본의 독립성
    • 깊은 복사된 객체는 원본 객체와 독립적이므로, 한 쪽에서의 변경이 다른 쪽에 영향을 미치지 않는다. 이는 불변성을 유지하는 데 유용하다.

ConcurrentDictionary.TryAdd 메서드

  • 새로운 키-값 쌍을 추가할 때 사용한다.
public bool TryAdd(TKey key, TValue value);
  • key: 추가할 항목의 키이다.
  • value: 추가할 항목의 값이다.
  • 반환값: bool 타입의 값으로, 추가 작업이 성공했는지 여부를 나타낸다.

동작 방식

  • TryAdd 메서드는 ConcurrentDictionary에 새로운 항목을 추가하려고 할 때, 해당 키가 이미 존재하는지 검사하고, 존재하지 않는 경우에만 항목을 추가한다.
    1. 키가 존재하지 않는 경우
      • 키-값 쌍이 사전에 추가된다.
      • TryAdd 메서드는 true를 반환한다.
    2. 키가 이미 존재하는 경우
      • 기존 항목이 변경되지 않는다.
      • TryAdd 메서드는 false를 반환한다.

주요 특징 및 주의점

  • 스레드 안정성
    • ConcurrentDictionary는 여러 스레드가 동시에 항목을 추가하거나 수정할 수 있는 상황에서도 안전하게 작동한다.
    • 내부적으로 적절한 락킹 메커니즘을 사용하여 데이터 일관성을 보장한다.
  • 원자성
    • TryAdd 메서드는 원자적으로 실행된다. 즉, 다른 스레드가 동시에 사전에 항목을 추가하려고 해도 이 메서드는 항목이 성공적으로 추가되었는지 여부를 정확하게 판단할 수 있다.
  • 성능
    • ConcurrentDictionary는 동시성 시나리오에서 높은 성능을 제공한다. 단일 스레드에서의 Dictionary와 비교할 때 약간의 성능 오버헤드가 있을 수 있지만, 멀티스레드 환경에서의 안전성과 효율성을 보장한다.

ConcurrentDictionary.AddOrUpdate(value1, value2, (k,v) ⇒ value2) 메서드

  • AddOrUpdate는 키가 존재하지 않으면 새 항목을 추가하고, 이미 존재하면 값을 업데이트하는 메서드이다.
  • value1
    • 추가하려는 키이다
  • value2
    • 키가 존재하지 않을 때 추가될 새로운 값이다.
  • (k, v) ⇒ value2
    • 키가 이미 존재할 때 실행되는 람다 함수이다.

동작

  • 만약 value1 키가 딕셔너리에 없다면, (value1, value2) 쌍을 새로 추가한다.
  • 만약 value1 키가 이미 존재한다면, 해당 키의 값을 value2로 업데이트 한다.
728x90

'Study > TIL(Today I Learned)' 카테고리의 다른 글

24.08.02 C#, DEV  (0) 2024.08.02
24.08.01 C#, 데이터베이스 샤딩  (0) 2024.08.01
24.07.30 C#, 배치 파일과 도스 명령어, 게임 서버  (1) 2024.07.30
24.07.29 C#, 게임 서버  (0) 2024.07.29
24.07.26 C#  (0) 2024.07.26