2009-12-05 2 views
3

여러분 중 일부는이 안내서에 대한 조언을 드릴 수 있기를 바랍니다.데이터베이스 또는 서비스에 대한 일괄 원격 호출을 수행하는 방법은 무엇입니까?

저는 웹 서비스 나 데이터베이스와 같은 원격 리소스를 호출해야하는 코드를 생성합니다.

(50) 어린이를위한 코드

class Parent{  
    IEnumerable<Child> Children; 

    int SumChildren() { 
     // note the AsParallel 
     return Children.AsParallel().Sum(c => c.RemoteCall()); 
    } 
} 

class Child {   
    public int RemoteCall() { 
     // call some webservice. I'd like to pool these calls 
     // without having to rewrite the rest of this code 
    } 
} 

이 조각을 고려, 오버 헤드 50 회 복용, 서비스에 50 개 통화를 할거야. 제 실제 생활의 예에서 이것은 쉽게 모든 일을 크롤링으로 가져 오는 백만 번 전화 일 수 있습니다.

나는 무엇을하고 싶습니다 전화 호출 스레드/작업에 대한 투명 어떤 방식으로 이러한 호출을 일괄 처리하고 싶습니다. 따라서 서비스를 직접 호출하는 대신이 호출을 일괄 처리하는 중앙 대기열 ('기차역')을 호출합니다.

이렇게하면 호출하는 작업이 차단됩니다. 그런 다음 대기열은 X 호출이 누적 될 때까지 대기 한 다음 요청 목록이있는 원격 서비스를 1 번 호출합니다.

결과가 오면이 큐는 반환 값을 올바른 작업으로 반환하고 해당 작업의 차단을 해제합니다. 호출 스레드의 경우이 모든 내용은 숨겨져 있으며 다른 함수 호출처럼 보입니다.

이 작업을 수행 할 수 있습니까? TPL에 이것을 할 수있게 해주는 기본 요소가 있습니까?

다른 것들이 완료되기를 기다리는 동시에 많은 일들이 진행되는 CCR과 같은 냄새가납니다.

물론이 코드를 다시 작성하여 부모 클래스에 대한 요청 목록을 만든 다음 서비스를 호출 할 수 있습니다. 문제는 실제 문제가 발생하면이 코드가 모두 생성된다는 것입니다. 그래서 Child.RemoteCall의 구현을 '내부에서 살펴 봐야'할 것입니다.이 모든 것을 훨씬 더 복잡하게 만듭니다. 또한 자식은 원격 객체에 대한 프록시 일 수 있습니다. 실행 가능하다면 매우 어려울 것입니다.이 복잡성을 분리하려고합니다.

호프는 누군가에게 의미가 있기를 바랍니다. 내가 정교하게 알려주지 않으면.

+0

나는 당신이 풀링을 의미한다고 생각하지 않습니까? 이는 연결을 지능적으로 공유하여 필요 이상으로 열거 나 닫지 않도록합니다 (ADO.NET 고유). 나는 당신이 실제로 일괄 처리 * 요청에 대해 이야기하고 있다고 생각하지만, 호출 앱 (사실상 일종의 프록시)에 대한 개념적으로 투명한 것으로 생각하십니까? – Murph

+0

당신은 일괄 처리에 대해 완전히 맞습니다. 텍스트를 변경했습니다. 고마워. – gjvdkamp

+0

100 만 통화 : 50 명의 자녀를 둔 부모 20,000 명과 1 백만 명의 자녀를 둔 부모 1 명 또는 부모에게 자녀가있는 자녀가 몇 명있는 나무 구조일까요? – richj

답변

1

이렇게하면 호출하는 작업이 차단됩니다. X는 큐가 X 호출을 수신하는 경우

를 축적 호출을 위해 다음 큐는 대기 (X < X) 만 원하는 하나의 작업이있는 경우 다른 작업이 전체> = X를 밀어 때까지 호출 작업이 차단됩니다 N * x 전화를 걸면 막히게됩니다.

응용 프로그램에 일반적으로 많은 작업이 실행되는 경우 비정상적으로 부하가 낮거나 클린 종료되는 경우에만이 문제가 간헐적으로 나타날 수 있습니다.

시간 제한을 추가하여이 문제를 해결할 수 있습니다. 따라서 제한 시간 내에 요청이 추가되지 않았거나 첫 번째 요청이 제한 시간보다 오래 대기 중이면 대기열에서 일괄 처리 된 요청을 보내 게됩니다.

물론이 코드를 다시 작성하여 부모 클래스에 대한 요청 목록을 만든 다음 서비스를 호출 할 수 있습니다.

아마도이 접근 방식을 통해 올바른 방향으로 가고있을 것입니다.생성 된 메소드 구현을 위임, 상속, 람다 메소드 또는 생성기 강화를 통해 직접 코딩 된 구현으로 대체하는 방법을 찾을 수 있습니까? 이 모든 코드가 생성됩니다 내 진짜 문제


....

코드의 어느 부분이 생성되고 (수정하기가 어렵습니까?) 코드의 어느 부분이이 문제를 해결할 수 있습니까?

  1. Child.RemoteCall()
  2. Parent.SumChildren()
  3. 상기의 어느.

위의 경우가 아니라면 문제를 해결하기 위해 무언가를 수정할 수 있어야합니다. 부모 및 자식 인스턴스가 AbstractFactory에 의해 작성 되었습니까? 그렇다면, 비헤이비어의 비 기능적 측면을 수정하는 데 사용할 수있는 프록시를 하위 인스턴스에 삽입 할 수 있습니다.

+0

안녕하세요, 리치, 그래, 분명히 대기열은 어쨌든 100ms 정도 후에 발생하므로 차단되지 않습니다. 나는 그것을 간결하게하기 위해 그것을 생략했다. 그것은 정말로 문제의 본질을 만지는 것이 아니기 때문이다. 다시 쓰기가 매우 어려울 수 있습니다. Child.RemoteMember의 내부 구현에는 메모가있을 수 있으므로 실제로 전화를 걸지 않아도됩니다. 또는 IChild, 원격 개체에 대한 프록시 일 수 있습니다. 컴파일시에는 알 수 없습니다. 이것들은 컴파일 타임을 재 작성하려고하는 것이 내가 생각했던 것보다 더 힘들어지는 2 가지 이유 일뿐입니다. 그래서이 작업을 수행 할 수 있는지보고 싶습니다. 어떤 아이디어? GJ – gjvdkamp

+0

이것은 구현의 비 기능적 측면 (원격 및 성능)을 숨기는 데 너무 성공적이었던 추상화의 예이기 때문에 자체적으로 흥미로운 질문을하게됩니다. 자식 인스턴스에 로컬에서 사용 가능한 미리 계산 된 응답이있는 경우 요청을 원격으로 처리하는 것이 적절하지 않습니다. 마찬가지로 이러한 요청을 일괄 처리하는 데 이점이 없습니다. 큐가이를 감지하고 즉시 (일괄 처리없이) 평가할 수 있다면 원격 요청을 일괄 적으로 처리 할 수 ​​있습니다. – richj

+0

이 링크를 발견했습니다 : http://msdn.microsoft.com/en-us/magazine/cc163340.aspx interesting. Tasks and Futures가이 문제에 대해 옳은 것인지 확실하지 않습니다. 그들은 도움이 될지 모르지만 완벽하지는 않습니다. 작업 관리자는 기본적으로 코어 당 하나의 스레드로 이루어 지지만 원격 요청에서는 일부 스레드가 차단되므로 코어 당 여러 스레드가 더 나은 처리량을 제공 할 수 있습니다. 서버의 코어 수가 클라이언트의 수보다 적합 할 수 있습니다. – richj

0

(답안 상자를 사용)

감사합니다.

"This would ... ...": 저장소에서 생성 된 코드를 처리합니다. 이 문제의 수작업으로 작성된 예제를 다룰 때 개발자는이를 발견하고 개선 할 수 있습니다. 코드 생성으로 일반적인 경우와 문제의 예제 세트를 추출하는 것은 꽤 어렵습니다. 이것은 꽤 복잡해지기 때문에 나의 전략은 벗어나서 정복 할 수 있습니다. 내가 문 밖으로 나가는 아이의 기능을 들여다 봐야한다면.

"내가이 링크를 찾았습니다 ...": 나는 Futures를 보았습니다.하지만 그것은 유휴 스레드가있을 때 병렬화 될 수있는 포크 메커니즘에 가깝습니다.

TPL은 작은 비트로 작업을 분할하는 것처럼 보입니다. 내가하고 싶은 일은이 비트들 중 일부를 다른 컴포지션에 넣은 다음 다시 병렬로 다시 분할하는 것입니다. (내 생각에, 아직도이 하나를 정신적으로 씹고있는 것 같아요 ...)

"하나 더 생각": 다시 말하자면, 편파와 정복 전략은 제가 이것을 멀리 할 수있게 해주는 것입니다. 그래서 나는 더 큰 문제를 작은 비트들로 나누고 그것을 풀어서 비트들을 다시 함께 넣습니다. 각 개미가 간단한 규칙 (또는 kanban, 비슷한 원리)을 따르는 개미 식민지를 생각해 봅니다. 중앙 관리 작업 (쿼리 최적화 프로그램)이 매우 복잡해지기 때문에 신속하게 속도가 느려지는 것과는 대조적입니다.

부모가 병렬화 가능한 방식으로 50 명의 자식을 호출 할 수있는 경우 이러한 별도의 작업은 훌륭한 원격 리소스를 가리키고 있기 때문에 함께 일괄 처리 될 수 있습니다.

주요 장애물은 호출하는 작업 (또는 스레드 또는 실행 단위) 블록을 차단하고 다른 일괄 처리 작업을 배치에 배치하고, 응답을 콜렉션에 넣는 방법입니다 모든 작업이 자신의 일을하고 다시 깨운다. (그리고 나서 효율적인 방식으로 ..).

나는 George Crysanthakopoulos (CCR을 만든 사람)가 수확량 계산서가 그가 그런 것에 익숙했던 것을 기억한다고 생각합니다. 나는 Channel9에서 그 인터뷰를 다시 찾으려고 노력할 것이다.

감사 GJ

+0

주요 장애물 : 자식이 원격 객체 인 경우 일괄 적으로 요청을 원격 서버로 보내면 (이상적으로 자식이 보낸 서버 프로세스에서 실행 됨) 결과가 계산 될 때 결과가 일괄 적으로 반환됨을 의미합니다 . 결과가 돌아올 때까지 호출 스레드가 차단되고 처리가 계속됩니다. 이것은 유일한 해결책은 아니지만 "주요 장애물"단락의 설명에 적절하게 매핑됩니다. – richj

+0

정확하게, 이것은 내가 가진 문제입니다. 어떻게 효율적으로 많은 미완성 'stackframes'가 배치가 돌아 오기를 기다리며 어떻게 스택에 응답을 다시 넣고 다시 실행하게합니까? 아직 다른 물건으로 바쁘기 때문에 아직 프로토 타입을 만들 수 없습니다. 감사합니다. GJ – gjvdkamp

3

당신은 대규모 병렬 프로그래밍의 표면에 긁힘된다. 당신은 concurrency oriented way에서 생각할 필요가 있습니다. 51 개의 일자리를 창출하고 있으며, 배치해야하는 50 개의 일자리가 아닙니다. 추가 작업은 50 개의 작업을 관리하는 작업입니다. 필요한 프리미티브에 관해서는 당신이 필요합니다.

JOBHANDLE X= GetJobId(); 
//single job 
AddJob(JOBHANLDE X,ChildJob y); 
//container of jobs 
AddJobs(JOBHANDLE x, ChildJobs Y); 

BeginAsyncExecute(JOBHANDLE X); 
WaitTillResult(JOBHANDLE X); 

당신은 (운영체제 커널에 의해 제공되는 것 이상으로) 차단 프리미티브를 정의하는 백그라운드에서 엔진을 필요로하고 그것의 모양에서 PLINQ 기술에 의해 처리되는, 실행하는 작업자 스레드와 작업을 관리합니다. PLINQ는 또한 좋은 녹색 실을 사용합니다.

당신은 데이터베이스와 웹 서버가 혼합되어 있다고 언급했습니다. 따라서 작업 프로세스/기능은 일괄 처리를 실행하기 전에 하위 작업을 올바른 리소스에 매핑해야합니다. 따라서 어린이는 일괄 처리가 가능한 RPC 호출 수가 훨씬 줄어들 수 있습니다.

그래서 작업 배치를 작성한 다음 차단합니다.

더 구체적인 것은 어렵습니다. 지금까지의 토론에 비추어 당신이 곤경에 처한 것을 말해주십시오.

+0

나는이 방법으로 내가 해왔 던 프로젝트에서 비슷한 해결책을 보았습니다. 원격 통화 전/통화 중 원하는 방법/방법을 변경해야 할 경우에도 유연성을 제공 할 것입니다. –

+0

안녕하세요, Hassan, 통찰력을 주셔서 감사합니다! 나는 사전에 사과해야한다. 나는 다른 물건들로 매우 바쁘다. 그래서이 dicussion을 나의 최대한의 관심을 끌 수 없다. 블로킹 프리미티브는 Richj가 도와 준 또 다른 문제가 있지만 생각하고있는 것입니다. 나는 물건의 나무를 가지고있다. 그리고 나는 그 나무에 표정 나무를 가지고있다. 빠른 런타임 코드에 대한 내 생각은 표현 트리를 원시 코드로 컴파일하는 것이 었습니다. 그러나 식 트리의 실행은 코드를 다시 작성하기 전에 항상 깊이가 있기 때문에 문제가 발생합니다. – gjvdkamp

+0

Futures는 실제로 검색을 시작하기에 좋은 장소라고 생각합니다. 실제 반환 값을 사용하기 전에 parallization을 허용하기 때문에 결과가 필요하기 전에 작업을 프레임 워크에 노출해야합니다. 또한 그들은 당신이 언급 한 '운영체제를 뛰어 넘는 차단 프리미티브'와 같은 냄새를 풍깁니다. 그래서 ServiceCallX() + ServiceCallY()는 다음과 같이됩니다. 미래 X {ServiceCallY}; X + Y; 이것은 원격 서비스에 대한 모든 호출을 별개의 비트로 멋지게 나눕니다. 하지만 지금은 원격 통화의 오버 헤드를 공유하는 배치로 어떻게 클러스터링합니까? – gjvdkamp

관련 문제