2012-06-28 2 views
1

저는 TPL Dataflow를 사용하여 최적의 아키텍처를 설계하는 최선의 방법을 묻고 싶습니다. 나는 아직 코드를 작성하지 않아서 게시 할 수있는 샘플 코드가 없다. 나는 (자원 봉사를하지 않는 한) 코드를 찾고 있지 않다 중 하나지만 설계에 도움이 많이 주시면 감사하겠습니다 다음과 같이가장 적합한 TPL 데이터 흐름 설계?

요구 사항은 다음과 같습니다

나는 특정 방법으로 서로에 의존하는 3 개 코어 블럭 (datablocks)이있다. Datablock1은 Foo1 유형의 객체를 생성하는 제작자입니다. Datablock2는 Foo1 객체 (Datablock1)를 구독하고 잠재적으로 (특정 Foo1이 아닌 모든 Foo1이 아닌) 잠재적으로 다른 데이터 블록이 소비 할 수 있도록 출력 대기열에 저장하는 Foo2 객체를 생성합니다. Datablock3은 또한 Datablock1에서 Foo1 객체를 사용하고 Datablock2가 Foo2 객체로 변환하여 Foo2 객체로 변환하는 Foo3 객체를 생성 할 수 있습니다. 생산 (FOO2), 소비된다 (FOO1 :

  • Datablock1가 : 생산 (FOO1)를 소모한다 (아무것도)
  • Datablock2이

    은 요약하면, 여기 블럭 (datablocks)과 그들이 각 생산 및 소비 있습니다 Foo3)

  • Datablock3는 : 생산 (Foo3) 소모한다 (FOO1)는

추가적인 요건은 동일 FOO1가 Datablock2 및 Datablock3에서 거의 동시에 처리된다는 점이다. Foo1 객체가 Datablock2에 의해 처음 소비되고 나서 Datablock2가 작업을 마치면 동일한 Foo1 객체가 작업을 수행하기 위해 Datablock3에 게시됩니다. Datablock2의 Foo2 객체는 Foo1 객체 나 Foo3 객체에 대한 연산에서 발생할 수 있습니다.

나는 그것이 의미가 있기를 바란다. 아직 불분명하다면 나는 더 설명하기를 기쁘게 생각한다.

첫 번째 아이디어는 3 개의 데이터 블록 각각에 대해 TPL Dataflowblocks를 만들고 다른 개체 유형의 들어오는 스트림을 처리하도록하는 것이 었습니다. 또 다른 아이디어는 데이터 블록을 분할하고 각 데이터 블록이 하나의 단일 객체 유형의 스트림 만 처리하도록하는 것입니다. 당신은 무엇을 권유합니까? 더 좋은 해결책이 있습니까?

Svick은 이미 Datablock1에서 도움을 받았으며 이미 작동 중입니다. 위에서 설명한대로 현재 환경을 TPL Dataflow로 바꾸는 방법에 대해서만 고민하고 있습니다.

모든 아이디어 나 조언을 부탁드립니다.

+1

가장 효율적인 아키텍처를 찾고 있다면 제대로 찾을 수있는 유일한 아키텍처가 있습니다. 어떤 옵션이 실제로 가장 적합한지를 확인하기 위해 다양한 옵션을 측정하십시오. 다른 모든 것은 추측 일뿐입니다. – svick

+0

완전히 동의하지만이 시점에서 데이터 블록이 연결된 다른 ISourceBlock의 객체를 받아들이도록 설정 될 수 있는지 여부는 확실하지 않습니다. 예를 들어 Foo1 및 Foo2 객체와 같이 사용할 수있는 데이터 블록을 작성하는 방법을 알고 있다면 2 개의 개별 입력 대기열에 버퍼링하고 전달 된 함수를 둘 중 하나에서 작동하게하면 몇 가지 테스트 아키텍처를 직접 설정할 수 있습니다. 문제는 현재 TPL Dataflow 문서가 거의 존재하지 않는다는 것입니다. Differentnet 객체를 하나의 Dataflowblock으로 전달하는 여러 제작자를 수락하는 방법을 다루는 방법을 도울 수 있습니까? –

+0

'Foo1'과'Foo3'는 공통 기본 클래스를 공유합니까? 그렇지 않다면 블록 2가 어떻게 둘 다 처리 할 수 ​​있을까요? – svick

답변

4

이 문제를 3 개로 나누고 각 문제를 개별적으로 해결해 보겠습니다.

첫 번째는 항목을 조건부로 생성하는 방법입니다. 가장 좋은 방법은 TransformManyBlock을 사용하고 함수가 하나 또는 하나의 항목이있는 콜렉션을 반환하도록하는 것입니다.

또 다른 옵션은 link the two blocks conditionally이므로 아무 것도 생산하지 않으려면 null을 무시하고 null을 반환하십시오. 그러나 그렇게한다면 null이 출력 버퍼에 남아 있지 않도록 소스를 NullTarget에 연결해야합니다.

두 번째 문제는 Foo1을 블록 # 2와 블록 # 3 모두로 보내는 방법입니다.여기서 두 가지 방법을 볼 수 있습니다.

  1. 두 대상 블록 (# 2 및 # 3)에 연결된 BroadcastBlock을 사용하십시오. BroadcastBlock에는 출력 대기열이 없으므로주의해야합니다. 따라서 대상 블록이 항목을 연기하면 처리하지 않습니다. 이 때문에이 경우 블록 # 2 및 # 3의 BoundedCapacity을 설정하면 안됩니다. 그렇게하지 않으면 연기되지 않으며 모든 메시지는 두 블록 모두에서 처리됩니다.
  2. 블록 # 2로 Foo1을 처리 한 후 수동으로 Post() (또는 그 이상, SendAsync()) 블록 # 3을 만듭니다.

TPL Dataflow는 "거의 같은 시점에서"정확히 무엇이 정확한지는 모르지만 일반적으로 TPL Dataflow는 독립 블록 처리 순서를 보증하지 않습니다. a custom TaskScheduler을 사용하여 다른 블록의 우선 순위를 변경할 수는 있지만 여기서는 유용 할 지 모르겠습니다.

마지막으로 가장 복잡한 문제는 단일 블록에서 다른 유형의 항목을 처리하는 방법입니다. 이 방법을 사용하는 방법에는 여러 가지가 있습니다. 어떤 것이 가장 적합할지 모르지만 다음 중 어떤 것이 가장 적합할지 모르겠습니다.

  1. 단일 블록으로 처리하지 마십시오. 하나는 TransformBlock<Foo1, Foo2>이고 다른 하나는 TransformBlock<Foo3, Foo2>입니다. 그런 다음 둘 다 BufferBlock<Foo2>에 연결할 수 있습니다.
  2. BatchedJoinBlock<Foo1, Foo3>batchSize이 1 인 결과로 Tuple<IList<Foo1>, IList<Foo3>>은 항상 Foo1 또는 Foo3 중 하나를 포함합니다.
  3. 보다 적합한 유형을 생성하는 TransformBlockBatchedJoinBlock을 연결하여 이전 솔루션을 향상시킵니다. Tuple<Foo1, Foo3> (항목 중 하나는 항상 null)이거나 F # Choice<Foo1, Foo3>과 같은 것으로 두 가지 중 하나만 설정됩니다.
  4. 새로운 블록 유형을 처음부터 새로 만들면 원하는대로 수행 할 수 있습니다. ISourceBlock<Foo2>이어야하며 ITarget<Foo3> 유형의 Target1 유형이 ITarget<Foo1>이고 Target2 인 빌트인 조인 블록과 같은 속성이 있어야합니다.

옵션 # 1 및 # 3을 사용하면 외부에서 # 4의 블록과 비슷한 단일 맞춤 블록으로 블록을 캡슐화 할 수 있으므로 더 쉽게 재사용 할 수 있습니다.

+0

"조건부로"생산한다는 의미를 명확히 할 수 있습니까? TransformBlocks는 일반적으로 입력 대기열에 도착하는 것보다 동일한 양의 항목을 출력 대기열에 배치하기 때문에 이것이 필요합니까? 조건에 대한 조치 블록 및 게시 사용은 더러운 해결책일까요? –

+0

"거의 같은 시간에"나는 DataBlock3에 의해 생성되고 DataBlock2에 의해 소비되는 Foo3은 Foo1에 의해 Datablock2에 설정된 특정 변수의 상태에 의존한다는 사실을 지적하고자했습니다. 이 문제를 해결할 수있는 유일한 방법은 데이터 블록 2와 3을 병합하는 것입니다. 또는 각 스트림 유형에 다른 데이터 블록을 사용하는 것입니다. –

+0

예, 조건부로 생성하면 일부 입력 만 출력을 생성합니다. TransformBlock은 소모하는 것과 동일한 양의 아이템을 생성합니다. 일반적으로 게시하는 것이 좋습니다.하지만이 경우 유효한 옵션 일 것입니다. – svick

관련 문제