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

C# 创建专用对象实例以在System.Threading.Tasks.Task中使用?,c#,multithreading,threadpool,C#,Multithreading,Threadpool,假设我有一个实例化成本非常高的业务对象,我永远不想在我的应用程序中创建超过10个该对象的实例。所以,这意味着我永远不希望同时运行超过10个并发工作线程 我想使用新的System.Threading.Tasks创建如下任务: var task = Task.Factory.StartNew(() => myPrivateObject.DoSomethingProductive()); 是否有一个样本可以说明如何: 创建TaskFactory使用的“对象池” 是否将TaskFactory限

假设我有一个实例化成本非常高的业务对象,我永远不想在我的应用程序中创建超过10个该对象的实例。所以,这意味着我永远不希望同时运行超过10个并发工作线程

我想使用新的System.Threading.Tasks创建如下任务:

 var task = Task.Factory.StartNew(() => myPrivateObject.DoSomethingProductive());
是否有一个样本可以说明如何:

  • 创建TaskFactory使用的“对象池”
  • 是否将TaskFactory限制为指定的线程数
  • 在对象池中锁定实例,使其一次只能由一个任务使用

  • 伊格比的回答让我从贾斯汀·埃瑟里奇那里了解到了这一点。这促使我写下这个示例:

    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;
        }
    }
    
    使用系统;
    使用System.Collections.Concurrent;
    使用System.Threading.Tasks;
    命名空间MyThreadedApplication
    {
    班级计划
    {
    静态void Main(字符串[]参数)
    {
    //构建10个昂贵工作对象实例的列表
    var expensiveStuff=新的BlockingCollection();
    对于(int i=65;i<75;i++)
    {
    费用增加(新的费用工作对象(转换为现金(i));
    }
    WriteLine(“{0}创建了昂贵的对象”,expensiveStuff.Count);
    //建立要执行的工作列表
    随机r=新随机();
    var work=新的ConcurrentQueue();
    对于(int i=0;i<1000;i++)
    {
    工作。排队(r.Next(10000));
    }
    WriteLine(“工作队列中的{0}项”,work.Count);
    //在15个线程中处理工作项列表
    对于(int i=1;i<15;i++)
    {
    Task.Factory.StartNew(()=>
    {
    while(true)
    {
    var expensiveThing=expensiveStuff.Take();
    尝试
    {
    int工作值;
    if(work.TryDequeue(out workValue))
    {
    费用化。嫁妆(工作价值);
    }
    }
    最后
    {
    费用增加(费用化);
    }
    }
    });
    }
    }
    }
    }
    类别费用工作对象
    {
    字符标识;
    公共无效工作(int someDelay)
    {
    系统。线程。线程。睡眠(someDelay);
    WriteLine(“{0}:{1}”,标识,someDelay);
    }
    公共费用工作对象(字符标识符)
    {
    标识=标识符;
    }
    }
    
    因此,我将BlockingCollection用作对象池,工作线程在独占控制一个昂贵的对象实例之前不会检查队列中是否有可用的工作。我认为这符合我的要求,但我真的很想得到比我更了解这方面的人的反馈…

    两个想法:

    有限并发调度器

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

    是此类调度器的一个很好的示例。我已经成功地使用了这个的修改版本

    对象池


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

    谢谢John,我没有意识到我很愚蠢。谁说您很愚蠢?我一直在研究并行扩展示例()中的示例.+1我将使用BlockingCollection,以便在池为空时尝试发出任务的线程被迫等待,直到任务返回到池中。延续可以实现循环。@Martin James,延续是否比在我上面的示例中使用try/finally“更安全”(或更好的编码实践)?@DavidMontgomery-不,try/finally可以。