正在创建专用对象实例以在System.Threading.Tasks.Task中使用
本文关键字:Task Tasks Threading 专用 创建 对象 实例 System | 更新日期: 2023-09-27 18:23:53
假设我有一个实例化成本很高的业务对象,并且我永远不想在我的应用程序中创建超过10个该对象的实例。因此,这意味着我永远不希望一次运行超过10个并发工作线程。
我想使用新的System.Threading.Tasks来创建这样的任务:
var task = Task.Factory.StartNew(() => myPrivateObject.DoSomethingProductive());
有没有一个样本可以展示如何:
- 创建一个"对象池"供TaskFactory使用
- 是否将TaskFactory限制为指定数量的线程
- 锁定对象池中的实例,使其一次只能由一个任务使用
Igby的回答让我看到了Justin Etheridge的这篇精彩的博客文章。这促使我写下这个样本:
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作为对象池,工作线程在对其中一个昂贵的对象实例拥有独占控制权之前,不会检查队列中的可用工作。我认为这符合我的要求,但我真的很想得到比我更了解这些东西的人的反馈…
两个想法:
有限并发调度程序
您可以使用自定义任务调度程序来限制并发任务的数量。在内部,它将分配多达n个任务实例。如果您传递给它的任务比它的可用实例多,它会将它们放入队列中。添加这样的自定义调度器是TPL的一个设计特性。
下面是这样一个调度器的好例子。我已经成功地使用了这个的修改版本。
对象池
另一种选择是使用对象池。这是一个非常相似的概念,只是不是将限制放在任务级别,而是将其放在对象实例的数量上,并强制任务等待空闲实例可用。这样做的好处是减少了创建对象的开销,但您需要确保以允许回收其实例的方式编写对象。您可以围绕并发生产者-消费者集合(如ConcurrentStack)创建一个对象池,消费者在该集合完成后将实例添加回该集合。