문제

다음 문제를 고려해보세요:데이터베이스에서 100개의 레코드를 가져와서 각 레코드에 대해 웹 서비스에서 업데이트된 정보를 가져와야 하는 프로그램이 있습니다.이 시나리오에서는 병렬 처리를 도입하는 두 가지 방법이 있습니다.

  1. 나는 새 스레드에서 웹 서비스에 대한 각 요청을 시작합니다.동시 스레드 수는 일부 외부 매개변수에 의해 제어됩니다(또는 어떻게든 동적으로 조정됩니다).

  2. 저는 더 작은 배치(각 레코드 10개)를 생성하고 각 배치를 별도의 스레드에서 시작합니다(예를 들어 스레드 10개).

어느 쪽이 더 나은 접근 방식이며, 그렇게 생각하는 이유는 무엇입니까?

도움이 되었습니까?

해결책

옵션 3이 가장 좋습니다.

비동기 IO를 사용하십시오.

요청 처리가 복잡하고 무겁지 않다면 프로그램은 HTTP 요청을 기다리는 데 시간의 99%를 소비하게 됩니다.

이것이 바로 Async IO가 설계된 목적입니다. Windows 네트워킹 스택(또는 .net 프레임워크 등)이 모든 대기 시간을 걱정하도록 하고 단일 스레드를 사용하여 결과를 전달하고 '선택'합니다.

불행하게도 .NET 프레임워크는 정말 골치아픈 일입니다.원시 소켓이나 Win32 API를 사용하는 경우 더 쉽습니다.어쨌든 C#3을 사용한 (테스트된!) 예제는 다음과 같습니다.

using System.Net; // need this somewhere

// need to declare an class so we can cast our state object back out
class RequestState {
    public WebRequest Request { get; set; }
}

static void Main( string[] args ) {
    // stupid cast neccessary to create the request
    HttpWebRequest request = WebRequest.Create( "http://www.stackoverflow.com" ) as HttpWebRequest;

    request.BeginGetResponse(
        /* callback to be invoked when finished */
        (asyncResult) => { 
            // fetch the request object out of the AsyncState
            var state = (RequestState)asyncResult.AsyncState; 
            var webResponse = state.Request.EndGetResponse( asyncResult ) as HttpWebResponse;

            // there we go;
            Debug.Assert( webResponse.StatusCode == HttpStatusCode.OK ); 

            Console.WriteLine( "Got Response from server:" + webResponse.Server );
        },
        /* pass the request through to our callback */
        new RequestState { Request = request }  
    );

    // blah
    Console.WriteLine( "Waiting for response. Press a key to quit" );
    Console.ReadKey();
}

편집하다:

.NET의 경우 '완료 콜백'은 실제로 기본 스레드가 아닌 ThreadPool 스레드에서 실행되므로 여전히 모든 공유 리소스를 잠가야 하지만 스레드 관리에 따른 모든 수고를 덜 수 있습니다.

다른 팁

고려해야 할 두 가지 사항.

1.기록을 처리하는 데 얼마나 걸리나요?

레코드 처리가 매우 빠른 경우 레코드를 스레드로 전달하는 오버헤드로 인해 병목 현상이 발생할 수 있습니다.이 경우 레코드를 너무 자주 넘겨줄 필요가 없도록 레코드를 묶는 것이 좋습니다.

레코드 처리가 합리적으로 오래 실행되는 경우 차이는 무시할 수 있으므로 더 간단한 접근 방식(스레드당 레코드 1개)이 아마도 가장 좋습니다.

2.몇 개의 스레드를 시작할 계획인가요?

스레드 풀을 사용하지 않는 경우 스레드 수를 수동으로 제한하거나 데이터를 큰 덩어리로 나누어야 한다고 생각합니다.모든 레코드에 대해 새 스레드를 시작하면 레코드 수가 커지면 시스템이 스래싱됩니다.

프로그램을 실행하는 컴퓨터는 병목 현상이 아닐 가능성이 높으므로 다음과 같습니다.HTTP 프로토콜에는 동일한 소켓에서 여러 GET 요청을 보낼 수 있는 연결 유지 헤더가 있어 TCP/IP 핸드 셰이크를 방지할 수 있다는 점을 기억하세요.불행히도 나는 .net 라이브러리에서 그것을 사용하는 방법을 모릅니다.(가능해야 합니다.)

또한 귀하의 요청에 대한 답변이 지연될 수도 있습니다.서버에 대해 항상 지정된 수의 미해결 요청이 있는지 확인할 수 있습니다.

받기 병렬 Fx.BlockingCollection을 살펴보세요.스레드를 사용하여 레코드 일괄 처리를 제공하고 1~n개의 스레드가 컬렉션에서 레코드를 가져와 서비스를 제공합니다.컬렉션이 공급되는 속도와 웹 서비스를 호출하는 스레드 수를 제어할 수 있습니다.ConfigSection을 통해 구성 가능하게 만들고 컬렉션 Action 대리자를 제공하여 일반화하면 마음껏 재사용할 수 있는 멋진 작은 배처를 갖게 됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top