C#의 Parallel API를 이용하여 CPU 100% 활용하기

CPU는 여러 개의 Core로 구성되어 있고 각 Core 단위로 동시에 연산을 처리할 수 있습니다. C#에서 CPU를 최대한 이용하기 위해서 Parallel API를 이용한 코드를 정리합니다.

Task.Factory.StartNew(() => {
    Parallel.ForEach(addressData, new ParallelOptions { MaxDegreeOfParallelism = cntCores },
        (task) => {
            int iAddress = task.Index;
            string Address = task.Address;
            
            /* 
                시간이 많이 걸리는 연산을 처리하는 스코프
            */

            Invoke(new Action(() => {
                // UI 처리가 가능한 스코프
            }));

            //Application.DoEvents(); -> 더 이상 필요치 않음
        }
    );
});

중요한 점은 Parallel에서 만들어진 스레드는 Main 스레드에서 구동되면 안됩니다. 그래서 Task.Factory.StartNew를 통해 별도의 스레드를 하나 만들고.. 만들어진 스레드에서 Parallel의 스레드를 구동하게 합니다. Task.Factory.StartNew를 사용한 이유는 스레드를 간단하게 만들 수 있기 때문으로 다른 스레드를 만드는 코드도 유효합니다. addressData는 스레드를 통해 처리해야할 데이터가 담긴 컨테이너입니다. 예를 들어 다음과 같습니다.

List<ADDRESS_DATA> addressData = new List<ADDRESS_DATA>();

ADDRESS_DATA는 다음과 같구요. (올바른 캡슐화를 적용하지 않은 코드입니다)

private class ADDRESS_DATA
{
    public int Index;
    public String Address;

    public ADDRESS_DATA(int Index, String Address)
    {
        this.Index = Index;
        this.Address = Address;
    }
}

Paralleld의 ForEach 매서드에서 task를 통해 ADDRESS_DATA의 필드값에 접근할 수 있습니다. 그리고 cntCores는 CPU의 코어 수인데, 동시에 실행할 수 있는 스레드의 개수로 지정하기 적당한 값입니다. 다음처럼 얻을 수 있습니다.

int cntCores = Environment.ProcessorCount;

Rust 개발 환경 구성

VS.Code를 이용하므로 이 사이트에서 Rust 개발환경 구성을 참조하였음.

매우 간단한데 rustup-init.exe를 다운로드 받아 실행시키면 콘솔에서 설치가 진행됨. Rust 컴파일러와 Cargo 실행 파일 등이 최신 버전으로 설치가 되며 Path까지 잡아줌. 나중에 Uninstall은 어찌하라는 것인지… 그냥 폴더와 Path 잡힌 것만 제거하면 되는 것인가? VS.Code에서 확장은 rust-analyzer와 CodeLLDB를 설치해주면 됨. 각각 코드 하일라이팅 등의 기능 제공과 디버깅 기능을 제공함.

Rust 프로젝트를 하나 생성하기 위해서는 콘설에서 다음 코드를 실행하면 됨. 원하는 폴더에서 아래 명령을 실행하면 hello_world라는 폴더가 만들어지고 필요한 파일도 생성됨.

cargo new hello_world

VS.Code를 실행하고 hello_world 폴더를 열면 됨. 그리고 컴파일은 VS.Code의 Shell에서 다음 명령을 실행하면 됨. 아래 명령을 통해 실행 파일이 만들어짐.

cargo build

컴파일과 함께 실행을 동시에 하고 싶다면 다음 명령.

cargo run

물론 VS.Code에서도 그냥 실행이 가능하고 라인 단위 디버깅도 가능함. (단, launch.json 파일 생성이 필요하고 앞서 언급한 CodeLLDB 확장 기능 설치가 필요함.