모든 시뮬레이션 클라이언트가 서버에 대해 미리 정의 된 루틴을 실행하는 클라이언트 시뮬레이션 프로그램을 작성 중입니다. 웹 서버는 4 개의 인스턴스가있는 푸른 하늘에서 실행됩니다.
모든 시뮬레이트 된 클라이언트는 서버에 연결된 후 동일한 루틴을 실행합니다.
언제든지 내 프로그램을 사용하여 300 ~ 800 명의 고객을 시뮬레이션하고 싶습니다.
내 질문은 : 클라이언트 클래스의 인스턴스 N 개를 생성하고 N 개의 다른 스레드에서 실행해야합니까? 또는
작업 라이브러리를 사용하여 작업을 수행해야합니까?
확실히 800 개의 스레드를 생성해서는 안됩니다.
여기서 다시 한 번 조치합시다. "클라이언트"에서 "요청"을 받아 "응답"을 해당 클라이언트로 다시 보내는 "서버"라는 장치가 있습니다. 요청은 우체국에서 배달 한 종이라고 가정하고 응답은 우체국에서 배달 한 책이 들어있는 상자입니다.
너는시뮬레이션하다800 클라이언트를 테스트하여 서버를 테스트합니다.
스레드가 사람이고 프로세서가 의자라고 가정 해 봅시다. 사람은 의자에 앉아있는 동안에 만 작업을 할 수 있습니다.
800 개의 쓰레드를 만드는 것은 800 명을 고용하고 고용하고, 각각에게 서버에 서신을 보내는 데 돈을 쓰는 것과 같습니다. 하지만 당신은 의자가 4 개 밖에 없기 때문에 의자를 사용하여 800 명이 모두 돌아 가야합니다.
그것은쑥스러운솔루션입니다. 쓰레드는 사람들과 마찬가지로현저하게 비싼. 작성한 스레드 수를 최소화해야합니다.
따라서 작업 팩토리를 통해 800 개의 작업을 생성하고 TPL로 작업을 병렬화해야합니까?
아니, 그렇게해서는 안된다. TPL에는 사람들을 끌어 들이기위한 풀 (pool)이 있으며, 그것들은 앉을 수있는 의자가있는 것보다 더 많은 인원이 급여되지 않도록 배치합니다. 그러나 당신의 임무는 "의자에 묶여 있지 않습니다"- - 사람들은 의자에 앉아서 서버에 요청을 보낸 다음 응답이 다시 오기를 기다리는 동안 의자에서 나올 것입니다.기다리는 동안 TPL은 이제 추가 작업을 처리하기 위해 더 많은 인력을 고용해야합니다.
웹 서버를 친다는 것은 I / O 경계입니다.CPU 바운드 작업에 대해서만 스레드 풀 작업을 생성해야합니다.
올바른 해결책은 고용하는 것입니다.두사람들.
한 사람, 즉 "I / O 완료 스레드"는 사서함에 요청을 삭제하고 들어오는 패키지를 확인하는 것 외에는 아무 작업도 수행하지 않습니다. 다른 사람, 즉 "시뮬레이션"사람은 800 명의 클라이언트를 시뮬레이션하기 위해 올바른 "일정"을 산출합니다. 시뮬레이션 담당자가 일정을 확인한 다음 잠자기 상태로 전환됩니다. 그녀는 서버에 또 다른 요청을 보낼 시간이되면 깨어 난다. 그녀는 깨어 났을 때 I / O 완료 스레드에게 편지함에이 편지를 놓으라고 지시하고 응답이 들어올 때 잠에서 깨 웁니다. 그런 다음 다른 요청 또는 응답을 보낼 때까지 잠자기 상태로 돌아갑니다 들어 와서 확인할 필요가 있습니다.
당신이해야 할 일은 (1) C #5의 베타 버전을 사용하고async/await
서버에 요청을 보내는 작업을 만든 다음 다른 요청을 보내거나 응답이 들어올 때까지 메시지 루프를 다시 제어합니다. 또는 C #5를 사용하고 싶지 않으면 Task Completion Source (작업 완료 소스)를 선택하고 적절한 연속성을 갖는 작업을 설정합니다.
즉, 많은 병렬 I / O 작업을 처리하는 올바른 방법은 매우 적은 수의 스레드를 생성하는 것이며, 각각의 스레드는 한 번에 아주 적은 양의 작업을 수행합니다. I / O 완료 스레드가 I / O의 세부 사항을 처리하게하십시오.800자를 보내는 것을 시뮬레이션하기 위해 800 명을 고용 할 필요가 없습니다.고용하다두사람들, 하나는 편지함을 쓰고 편지는 편지를 쓰는 사람.
이 경우의 대답은 그렇게 간단하지 않습니다. 실제로 클라이언트를 시뮬레이션하는 방법에 달려 있습니다.
800 개의 클라이언트를 연결하고 싶지만 반드시 같은 시간에 연결해야하는 것은 아닙니다.Task
에스. 그것들은 가볍고 근원적 인 것들을 효율적으로 사용한다.ThreadPool
.
클라이언트가 절대적으로 모든 것을 병렬로 수행하기를 원한다면 실제로 쓰레드를 피할 방법이없는 것 같습니다. 800 개의 경량 동시 실행 작업을 수행하는 마술 같은 방법은 없습니다. 그만큼Task
추상화는 스레드 풀을 사용하기 때문에 가볍습니다. 즉, 많은 작업이 소수의 실제 스레드에 매핑됩니다. 그러나 물론 이것은 실제로 병렬로 실행되지는 않지만 가능할 때마다 실행되도록 예정되어 있음을 의미합니다. 그만큼ThreadPool
250 (AFAIK)의 최대 스레드 수를 가지므로 사용하는 경우 한 번에 250 개의 "클라이언트"가 실제로 실행되지 않습니다.Task
에스. 이 솔루션은 최대 스레드 수를 800으로 설정하지만이 시점에서 클래식 스레드를 사용하는 것과 같습니다.
태스크 라이브러리를 사용하고 태스크 라이브러리가 모든 스레딩을 처리하도록합니다. 당신은 800 개의 스레드를 회전시키고 싶지 않습니다. 한 번에 많은 동시 스레드가 진행되는 것은 좋지 않은 생각입니다. 여기에 또 다른 스택 오버플로 질문이 있습니다..NET 응용 프로그램의 최대 스레드 수는 얼마입니까?
이것을 위해응용 프로그램 도메인최선의 방법입니다.
안응용 분야.NET 응용 프로그램이 실행되는 격리 런타임 단위입니다. 관리되는 메모리 경계, 응용 프로그램 구성 설정을위한 컨테이너는 물론 분산 응용 프로그램을위한 통신 인터페이스를 제공합니다.
각 .NET 응용 프로그램은 대개 지정된 프로세스 / 프로그램이 시작될 때 CLR에 의해 자동으로 만들어지는 하나의 응용 프로그램 도메인 만 호스팅합니다. 단일 프로세스 / 프로그램에 추가 응용 프로그램 도메인을 만드는 것이 유용 할 때도 있습니다. 여러 응용 프로그램 도메인을 사용하면 통신의 복잡성을 피할 수 있으며 여러 개별 프로세스를 사용하고 작업을 격리 할 수 있습니다.
원하는 것을 위해 두 가지 옵션이 있습니다.
이는 스레드 안전성에 매우 지쳐 있어야한다는 것을 의미합니다. 다중 로그인을 시뮬레이트하고 클라이언트를 시뮬레이트하는 등의 작업은 매우 어려울 것입니다.
이렇게하면 각 회전 스레드가 격리되고 호스팅 응용 프로그램 / 프로그램에서 쉽게 액세스 할 수 있습니다. 여러분 모두 X 개의 시뮬레이션을 X 개의 개별 응용 프로그램 도메인에 포함시킴으로써 각 도메인은 격리되어 정적 클래스 멤버 등을 통해 다른 클라이언트 시뮬레이션을 방해 할 수 없습니다.
다음은 Joseph Albahari의 저서에서 발췌 한 내용입니다C #4.0 In a Nutshell다음과 같이하는 것이 좋습니다.
40 개의 동시 클라이언트 시뮬레이션 예제가 유용 할 수 있습니다.
class program
{
static void main()
{
// Create 40 domains and 40 threads.
AppDomain[] domains = new AppDomain[40];
Thread[] thread = new Thread[40];
for (int i = 0; i < 40; i++)
{
domains[i] = AppDomain.CreateDomain("Client Simulation " + i);
thread[i] = new Thread(SimulateClientInOtherDomain);
}
// Start all threads, passing to each thread its app domain.
for (int j = 0; j < 40; j++)
threads[j].Start(domains[j]);
// Wait for the threads to finish.
for (int k = 0; k < 40; k++)
threads[k].Join();
// Unload the application domains.
for (int l = 0; l < 40; l++)
AppDomain.Unload(domains[l]);
}
// Thread start with input of with domain to run on/in.
static void SimulateClientInOtherDomain(object domain)
{
((AppDomain)domain).DoCallBack(Simulate);
}
static void Simulate()
{
Client simClient1 = new Client("Bill", "Gates", ...);
simClient1.Simulate();
}
}
이게 도움이 되길 바란다.