嵌套线程(任务)过早地过时

时间:2016-04-27 18:52:00

标签: c# .net multithreading task

我有以下代码,我不相信它的重要性,但我的行为很奇怪。

当我在单独的线程上运行几个月时,它运行正常(如何在下面),但是当我多年来多线程(取消注释任务)时,它每次都会超时。超时设置为5分钟,持续数月/ 20分钟,并且会在一分钟内超时。

这种行为是否有已知原因?我错过了一些简单的东西吗?

    public List<PotentialBillingYearItem> GeneratePotentialBillingByYear()
    {
        var years = new List<PotentialBillingYearItem>();
        //var tasks = new List<Task>();
        var startYear = new DateTime(DateTime.Today.Year - 10, 1, 1);
        var range = new DateRange(startYear, DateTime.Today.LastDayOfMonth());

        for (var i = range.Start; i <= range.End; i = i.AddYears(1))
        {
            var yearDate = i;
            //tasks.Add(Task.Run(() =>
            //{
                years.Add(new PotentialBillingYearItem
                {
                    Total = GeneratePotentialBillingMonths(new PotentialBillingParameters { Year = yearDate.Year }).Average(s => s.Total),
                    Date = yearDate
                });
            //}));
        }

        //Task.WaitAll(tasks.ToArray(), TimeSpan.FromMinutes(20));

        return years;
    }

    public List<PotentialBillingItem> GeneratePotentialBillingMonths(PotentialBillingParameters Parameters)
    {
        var items = new List<PotentialBillingItem>();
        var tasks = new List<Task>();
        var year = new DateTime(Parameters.Year, 1, 1);
        var range = new DateRange(year, year.LastDayOfYear());

        range.Start = range.Start == range.End ? DateTime.Now.FirstDayOfYear() : range.Start.FirstDayOfMonth();

        if (range.End > DateTime.Today) range.End = DateTime.Today.LastDayOfMonth();

        for (var i = range.Start; i <= range.End; i = i.AddMonths(1))
        {
            var firstDayOfMonth = i;
            var lastDayOfMonth = i.LastDayOfMonth();
            var monthRange = new DateRange(firstDayOfMonth, lastDayOfMonth);
            tasks.Add(Task.Run(() =>
            {
                using (var db = new AlbionConnection())
                {

                    var invoices = GetInvoices(lastDayOfMonth);

                    var timeslipSets = GetTimeslipSets();

                    var item = new PotentialBillingItem
                    {
                        Date = firstDayOfMonth,
                        PostedInvoices = CalculateInvoiceTotals(invoices.Where(w => w.post_date <= lastDayOfMonth), monthRange),
                        UnpostedInvoices = CalculateInvoiceTotals(invoices.Where(w => w.post_date == null || w.post_date > lastDayOfMonth), monthRange),
                        OutstandingDrafts = CalculateOutstandingDraftTotals(timeslipSets)
                    };

                    items.Add(item);
                }
            }));
        }

        Task.WaitAll(tasks.ToArray(), TimeSpan.FromMinutes(5));

        return items;
    }

1 个答案:

答案 0 :(得分:0)

您可以考虑预先分配更多数量的线程池线程。线程池分配新线程的速度非常慢。下面的代码只运行10秒(理论上的最小值),将最小线程池线程数设置为2.5k,但注释掉SetMinThreads会使它超过1:30秒。

static void Main(string[] args)
{
    ThreadPool.SetMinThreads(2500, 10);
    Stopwatch sw = Stopwatch.StartNew();
    RunTasksOutter(10);
    sw.Stop();
    Console.WriteLine($"Finished in {sw.Elapsed}");
}

public static void RunTasksOutter(int num) => Task.WaitAll(Enumerable.Range(0, num).Select(x => Task.Run(() => RunTasksInner(10))).ToArray());
public static void RunTasksInner(int num) => Task.WaitAll(Enumerable.Range(0, num).Select(x => Task.Run(() => Thread.Sleep(10000))).ToArray());

你也可能用完了线程池线程。 Per:https://msdn.microsoft.com/en-us/library/0ka9477y(v=vs.110).aspx其中一次不使用线程池(由任务使用)是:

  

您的任务导致线程长时间阻塞。线程池具有最大线程数,因此大量被阻塞的线程池线程可能会阻止任务启动。

由于在这些线程上进行IO,可以考虑用异步代码替换它们或者用LongRunning选项启动它们吗? https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskcreationoptions(v=vs.110).aspx