假设我有一个实例化非常昂贵的业务对象,我绝不想在我的应用程序中创建超过该对象的10个实例。所以,这意味着我永远不会希望一次运行超过10个并发工作线程。
我想使用新的System.Threading.Tasks来创建这样的任务:
var task = Task.Factory.StartNew(() => myPrivateObject.DoSomethingProductive());
那里有样品会显示如何:
Igby的回答让我从Justin Etheridge那里得到了excellent blog post。然后促使我写这个样本:
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
namespace MyThreadedApplication
{
class Program
{
static void Main(string[] args)
{
// build a list of 10 expensive working object instances
var expensiveStuff = new BlockingCollection<ExpensiveWorkObject>();
for (int i = 65; i < 75; i++)
{
expensiveStuff.Add(new ExpensiveWorkObject(Convert.ToChar(i)));
}
Console.WriteLine("{0} expensive objects created", expensiveStuff.Count);
// build a list of work to be performed
Random r = new Random();
var work = new ConcurrentQueue<int>();
for (int i = 0; i < 1000; i++)
{
work.Enqueue(r.Next(10000));
}
Console.WriteLine("{0} items in work queue", work.Count);
// process the list of work items in fifteen threads
for (int i = 1; i < 15; i++)
{
Task.Factory.StartNew(() =>
{
while (true)
{
var expensiveThing = expensiveStuff.Take();
try
{
int workValue;
if (work.TryDequeue(out workValue))
{
expensiveThing.DoWork(workValue);
}
}
finally
{
expensiveStuff.Add(expensiveThing);
}
}
});
}
}
}
}
class ExpensiveWorkObject
{
char identity;
public void DoWork(int someDelay)
{
System.Threading.Thread.Sleep(someDelay);
Console.WriteLine("{0}: {1}", identity, someDelay);
}
public ExpensiveWorkObject(char Identifier)
{
identity = Identifier;
}
}
因此,我使用BlockingCollection作为对象池,并且工作线程在对其中一个昂贵的对象实例进行独占控制之前不会检查队列中的可用工作。我认为这符合我的要求,但我真的很喜欢那些比我更了解这些东西的人的反馈......
答案 0 :(得分:2)
两个想法:
有限并发调度程序
您可以使用自定义任务计划程序来限制并发任务的数量。在内部,它将分配最多 n 任务实例。如果您传递的任务多于可用实例,则会将它们放入队列中。添加这样的自定义调度程序是TPL的设计特性。
Here是这种调度程序的一个很好的例子。我成功地使用了这个的修改版本。
对象池
另一种选择是使用对象池。这是一个非常相似的概念,除了不是将限制放在任务级别,而是将其放在对象实例的数量上,并强制任务等待免费实例变得可用。这有利于减少对象创建的开销,但是您需要确保以允许回收它的实例的方式编写对象。您可以围绕并发生产者 - 消费者集合创建对象池,例如ConcurrentStack,消费者在完成后将实例添加回集合。