2009-08-19 1 views
0

제목이 맞는지는 모르지만 필자가 작성한 앱에는 (확장) 메소드가 많이 있습니다. 간단한 예 :자동 루핑 구현

객체 :

Matter (Burn, Explode, Destroy, Freeze, Heat, Cool) 
Atom (Attach, Detach) 
<many more> 

와 같은 사용자 지정 컬렉션 : 이와 같은

ImmutableList<T> 

및 방법 :

당신이 볼 수 있듯이
public static class Burner 
{ 
    public static Matter Burn (this Matter matter) 
    { 
     // matter is burning ... 
    } 
} 

var matters = new ImmutableList<Matter>(); 
matters.Burn(); 

, 굽기 작업에 단일 개체이지만 여전히 ImmutableList에 나타납니다. 그렇게하면 필자는 평행선을 병렬로 관리하려고한다.

가장 효과적인 방법, 가장 깨끗한 방법, 가장 유지하기 쉬운 방법 또는 결합하는 방법은 무엇입니까?

처음에는 각 클래스 (버너 등) 내에서 ImmutableList를 사용하는 다른 확장 메서드를 정의하지 않으려합니다. 수백 개가 수백 개이기 때문에 동일하게 보일 것입니다. 그러나 나는 아이디어에 열중하고 있습니다.

또한 모든 코드는 내 것이므로 확장 메소드가 아닌 코드의 모든 부분에서 아무 것도 변경하거나 추가 할 수 있습니다. ForEach의 자신의 구현

matters.ForEach(Burner.Burn); 

잘못 무엇

답변

2

? 당신은 PLINQ 또는 뭔가를 사용하려는 해달라고하면

+0

고마워요.하지만 ForEach는 병렬이 아니므로 앱의 특정 요구 사항에 맞춰 자체 병렬 처리를 관리하고 싶습니다. 또한 가능한 경우 내 게시물의 구문을 사용합니다. –

+0

어쩌면 내가 당신의 문제를 정확하게 이해하지 못할 수도 있지만, 당신 자신의'ForEach' 메소드를 구현하지 못하게하는 것은 무엇일까? – dtb

+0

나는 할 수 있었다. 그러나 나는 다음과 같은 구문을 갖고 싶다. matter.Burn(); 그렇지 않으면 코드에 ForEach 호출이 많이있을 것입니다. 나쁜 것은 아니지만 "직접"호출, 따라서 확장 메서드를 원하는 것은 매우 분명합니다. –

1

간단한 클래스 다음 자신의 ForEachParallel 확장을 생성하는 병렬 방식으로 반복합니다.

엠레 Aydinceren

사용법 :

Parallel.ForEach (문제, 문제 => matter.Burn());

또는

matters.ParallelForEach (물질 => matter.Burn());

/// <summary> 
/// Provides concurrent processing on a sequence of elements 
/// </summary> 
public static class Parallel 
{ 
    /// <summary> 
    /// Number Of parallel tasks 
    /// </summary> 
    public static int NumberOfParallelTasks; 


    static Parallel() 
    { 
     NumberOfParallelTasks = Environment.ProcessorCount < 65 ? Environment.ProcessorCount : 64; 
    } 

    /// <summary> 
    /// Performs the specified action on each element of the sequence in seperate threads. 
    /// </summary> 
    /// <typeparam name="T">The type of the elements of source.</typeparam> 
    /// <param name="source">A sequence that contains elements to perform action</param> 
    /// <param name="action">The Action delegate to perform on each element of the IEnumerable.</param> 
    public static void ForEach<T>(IEnumerable<T> source, Action<T> action) 
    { 
     if(source == null) return; 

     //create a new stack for parallel task we want to run , stack is very performant to add and read elements in sequence 
     var stacks = new Stack<T>[NumberOfParallelTasks]; 

     //instantiate stacks 
     for(var i = 0;i < NumberOfParallelTasks;i++) 
     { 
      stacks[i] = new Stack<T>(); 
     } 

     var itemCount = 0; 

     //spread items in source to all stacks while alternating between stacks 
     foreach(var item in source) 
     { 
      stacks[itemCount++ % NumberOfParallelTasks].Push(item); 
     } 

     if(itemCount==0)return; 

     //if we have less items than number of Parallel tasks we should only spun threads for active stacks 
     var activeStackCount = itemCount < NumberOfParallelTasks ? itemCount : NumberOfParallelTasks; 

     //events are used to notify thread pool completed 
     var events = new ManualResetEvent[activeStackCount]; 

     for(var index = 0;index < activeStackCount;index++) 
     { 
      //assign index to a scope variable otherwise in multithreading index will not be consistant 
      var listIndex = index; 

      events[listIndex] = new ManualResetEvent(false); 

      ThreadPool.QueueUserWorkItem(delegate 
      { 
       //name the thread for debugging 
       if(String.IsNullOrEmpty(Thread.CurrentThread.Name)) 
       { 
        Thread.CurrentThread.Name = String.Format("Parallel.ForEach Worker Thread No:{0}", listIndex); 
       } 

       try 
       { 
        //iterate through our stack 
        var stack = stacks[listIndex]; 
        foreach(var item in stack) 
        { 
         action(item); 
        } 
       } 
       finally 
       { 
        //fire the event to signal WaitHandle that our thread is completed 
        events[listIndex].Set(); 
       } 

      }); 
     } 

     WaitAll(events); 

    } 

    private static void WaitAll(WaitHandle[] waitHandles) 
    { 
     if(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) 
     { 
      for(var index = 0;index < waitHandles.Length;index++) WaitHandle.WaitAny(waitHandles); 
     } 
     else 
     { 
      WaitHandle.WaitAll(waitHandles); 
     } 
    } 

    /// <summary> 
    /// Performs the specified action on each element of the sequence in seperate threads. 
    /// </summary> 
    /// <typeparam name="T">The type of the elements of source.</typeparam> 
    /// <param name="source">A sequence that contains elements to perform action</param> 
    /// <param name="action">The Action delegate to perform on each element of the IEnumerable.</param> 
    public static void ParallelForEach<T>(this IEnumerable<T> source, Action<T> action) 
    { 
     ForEach(source, action); 
    } 

} 
+0

하나의 동시성 인식 스택이 없어야합니다. 작업 및 스레드 풀로 구성됩니다. 각 스레드가 시작될 때 스택을 검사하여 작업합니다. 스택이 비어 있으면 종료합니다. 이 방법은 일부 작업이 길고, 일부 작업은 짧습니다. 10 개의 빠른 작업을 종료하고 종료하고 다른 10 개의 느린 작업을 모두 실행하는 하나의 스레드로 끝나지 않습니다. – jmucchiello

2

당신은 흥미로운 읽을 수 this article을 찾을 수 있습니다. 이 기사에서는 병렬 foreach가 작동하는 방법에 대해 설명합니다. 자신이 직접 수행하고 .NET 3.5의 경우 Parallel extensions CTP을 사용하는 방법에 대해 설명합니다. 그냥 자신의 프로젝트가 아니면

using System.Threading; 

// A simple string collection 
string[] numbers = { "One", "Two", "Three", "Four", "Five", "Six", "Seven", 
    "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen"}; 

// equivalent to: foreach (string n in numbers) 
Parallel.ForEach<string>(numbers, delegate(string n) 
{ 
    Console.WriteLine("n={0}", n.ToString()); 
}); 

당신은 어떤 경우에 당신은 아마 원하는한다 (생산 코드에 CTP를 사용하는 것을 주저한다 다음 CTP, 당신은이 (위의 문서에서 가져온 예를) 할 수있다 CTP를 시도하십시오).