正在创建专用对象实例以在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());

有没有一个样本可以展示如何:

  1. 创建一个"对象池"供TaskFactory使用
  2. 是否将TaskFactory限制为指定数量的线程
  3. 锁定对象池中的实例,使其一次只能由一个任务使用

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作为对象池,工作线程在对其中一个昂贵的对象实例拥有独占控制权之前,不会检查队列中的可用工作。我认为这符合我的要求,但我真的很想得到比我更了解这些东西的人的反馈…

正在创建专用对象实例以在System.Threading.Tasks.Task中使用

两个想法:

有限并发调度程序

您可以使用自定义任务调度程序来限制并发任务的数量。在内部,它将分配多达n个任务实例。如果您传递给它的任务比它的可用实例多,它会将它们放入队列中。添加这样的自定义调度器是TPL的一个设计特性。

下面是这样一个调度器的好例子。我已经成功地使用了这个的修改版本。

对象池

另一种选择是使用对象池。这是一个非常相似的概念,只是不是将限制放在任务级别,而是将其放在对象实例的数量上,并强制任务等待空闲实例可用。这样做的好处是减少了创建对象的开销,但您需要确保以允许回收其实例的方式编写对象。您可以围绕并发生产者-消费者集合(如ConcurrentStack)创建一个对象池,消费者在该集合完成后将实例添加回该集合。

相关文章: