如何限制创建的任务数量?

时间:2014-04-04 23:07:28

标签: c# asp.net task-parallel-library threadpool odp.net

我正在使用ODP.NET,它不提供任何asych方法,如SQL驱动程序或其他Oracle驱动程序。

我有很多慢查询,有时我需要在一个MVC控制器调用上调用其中几个。所以我试图将它们包装在Task调用中。所以我正在考虑使用这种模式:

(这是一个有点人为的例子,我不会将相同的查询称为10次真实,这将是一些异构工作负载)

List<Task<DbDataReader>> list = new List<Task<DbDataReader>>(10);
for (int i = 0; i < 10; i++)
{
    ERROR_LOG_PKG_DR package = new ERROR_LOG_PKG_DR();
    //Could be a bunch of different queries.
    //Returns a task that has the longrunningtask property set, so it's on it's own thread
    list.Add(package.QUERY_ALL_ASYNC());
}

Task.WaitAll(list.ToArray());

这是任务:

public Task<DbDataReader> QUERY_ALL_ASYNC()
{
    CancellationToken ct = new CancellationToken();
    return Task.Factory.StartNew(_ =>
                                     {               
                                         System.Diagnostics.Debug.WriteLine("InTask: Thread: " +
                                                                            Thread.CurrentThread.ManagedThreadId);
                                         System.Diagnostics.Debug.WriteLine("InTask: Is Background: " +
                                                                            Thread.CurrentThread.IsBackground);
                                         System.Diagnostics.Debug.WriteLine("InTask: Is ThreadPool: " +
                                                          Thread.CurrentThread.IsThreadPoolThread);
                                         return QUERY_ALL<DbDataReader>();
                                     }, null, ct,TaskCreationOptions.LongRunning, TaskScheduler.Default);
}

这会引发10个线程。如果我想要一些像行为一样的线程池 - 即。一次只有大约4个并发线程 - 重用线程等,但我希望它在ASP.NET线程池之外(用于服务请求)

我该怎么做?

3 个答案:

答案 0 :(得分:4)

如果您愿意牺牲Web应用程序的可伸缩性,可以使用SemaphoreSlim来限制并行任务的数量:

const int MAX_PARALLEL_TASKS = 4;

DbDataReader GetData(CancellationToken token)
{
    DbDataReader reader = ... // execute the synchronous DB API
    return reader;
}

// this can be called form an async controller method
async Task ProcessAsync()
{
    // list of synchronous methods or lambdas to offload to thread pool
    var funcs = new Func<CancellationToken, DbDataReader>[] { 
        GetData, GetData2, ...  };

    Task<DbDataReader>[] tasks;

    using (var semaphore = new SemaphoreSlim(MAX_PARALLEL_TASKS))
    {
        tasks = funcs.Select(async(func) => 
        {
            await semaphore.WaitAsync();
            try
            {
                return await Task.Run(() => func(token));
            }
            finally
            {
                semaphore.Release();
            }
        }).ToArray();

        await Task.WhenAll(tasks);
    }

    // process the results, e.g: tasks[0].Result
}

答案 1 :(得分:0)

我认为这就是你所需要的 - (msdn) How to: Create a Task Scheduler That Limits Concurrency

短暂的想法是创建自定义TaskScheduler,以限制同时运行任务的数量。

答案 2 :(得分:0)

为什么不只使用ThreadPool?

https://msdn.microsoft.com/en-us/library/kbf0f1ct.aspx

这提供了系统感知的限制,并且已经存在了很长时间