我不知道标题是否有意义,但在我写的应用程序中有很多(扩展)方法。一个简单的例子:
物件:
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();
正如您所看到的,Burn可以在单个实体上运行,但仍会出现在ImmutableList上。这样我想自己管理并行化(并行刻录)。
我如何以最高效的方式,最干净,最易维护的方式,或组合使用?
首先,我宁愿不定义另一个在每个类(Burner等)中使用ImmutableList的扩展方法,因为有数百个像这样的它们可能看起来一样。但我对这些想法持开放态度。
此外,所有代码都是我的,所以我可以在代码的任何部分更改/添加任何内容,而不仅仅是扩展方法。
答案 0 :(得分:2)
有什么问题
matters.ForEach(Burner.Burn);
使用您自己的ForEach
实现?
答案 1 :(得分:2)
您可能会发现this article是一本有趣的读物。它讨论了并行foreach如何工作,既可以自己动手也可以使用.NET 3.5的Parallel extensions CTP。使用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)。
答案 2 :(得分:1)
这是一个以并行方式迭代的简单类。
Emre Aydinceren用法:
Parallel.ForEach(事项,问题=&gt;问题.Burn());
或
matters.ParallelForEach(matter =&gt; 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);
}
}
答案 3 :(得分:0)
创建自己的ForEachParallel扩展,如果你不想使用PLinq或其他东西