异步编程和并行编程的性能锁定在单线程

本文关键字:编程 锁定 单线程 性能 并行 异步 | 更新日期: 2023-09-27 18:18:41

我正在为一个列表编写一些代码,该列表通过regex和DateTime元素解析字典。下面的代码确实可以工作,而且工作得相当好。然而,当我回去的时候,我注意到这种平行。每一个我都写过。我的问题很简单;使用并行是否有性能提升?如果我正在锁定线程?我觉得这似乎违背了整个目的。

同样,我觉得如果同样的想法/问题适用于异步情况,因为我正在锁定线程。

namespace StackOverflowExample
{
    public class ScheduledTimeList : List<ScheduledTime>
    {
        public static ScheduledTimeList Parse(
            Dictionary<string, string> dateTimeStrings, string startRegex,
            string endRegex, object sync)
        {
            var scheduledTimes = new ScheduledTimeList();
            Parallel.ForEach(from dt in dateTimeStrings.AsParallel()
                             select ParseScheduledTime(dt, startRegex, endRegex), dt =>
            {
                lock (sync) { scheduledTimes.Add(dt); }
            });
            return scheduledTimes;
        }
        private static ScheduledTime ParseScheduledTime(
            KeyValuePair<string, string> dateTime, string startRegex,
            string endRegex)
        {
            var startString =
                dateTime.Key + " " + new Regex(startRegex).Match(dateTime.Value);
            var endString =
                dateTime.Key + " " + new Regex(endRegex).Match(dateTime.Value);
            var startDateTime = DateTime.Parse(startString);
            var endDateTime = DateTime.Parse(endString);
            return new ScheduledTime(startDateTime,
                endDateTime);
        }
        private static async Task<ScheduledTime> ParseScheduledTimeAsync(
            KeyValuePair<string, string> dateTime, string startRegex,
            string endRegex)
        {
            var startString = Task.Run(() =>
                dateTime.Key + " " + new Regex(startRegex).Match(dateTime.Value).Value);
            var endString = Task.Run(() =>
                dateTime.Key + " " + new Regex(endRegex).Match(dateTime.Value).Value);
            await Task.WhenAll(startString, endString);
            var startDateTime = await Task.Run(() =>
                DateTime.Parse(startString.Result));
            var endDateTime = await Task.Run(() =>
                DateTime.Parse(endString.Result));
            return new ScheduledTime(startDateTime,
                endDateTime);
        }
    }
}

异步编程和并行编程的性能锁定在单线程

以下是一些误解、分析问题和错误决策。

首先,如果你开始类似Parallel。ForEach或AsParallel或Tasks,这几乎是相同的,所有运行在TPL之上,然后没有一个线程,但许多或一个,这一切都取决于负载平衡,但我的观点是,锁定并不能确保所有部分将在同一线程上运行。相反,锁确保在任何给定的时间内,只有一个线程将在锁定区域内运行。当然不是一回事

现在第二个问题是,你犯了初学者常犯的错误。引入过多的并发性并没有帮助。当然,我在Parse方法中看到一个问题,在那里你首先激发内部并行块来获得结果,如果AsParallel(), PLINQ,方法,在那里它完全并发地工作,但然后你返回IEnumerable并行。ForEach,强制PLINQ将结果同步回IEnumerable。这对性能来说是一个糟糕的决定。

第三个错误是在并发代码中使用List等旧集合。并发代码在并发集合上表现最好。在这里,它意味着使用ConcurrentBag而不是List。
 public class ScheduledTimeList : ConcurrentBag<ScheduledTime>

所以最后在Parse method:

中是这样的
var scheduledTimes = new ScheduledTimeList();
dateTimeStrings
.AsParallel()
.ForAll(dts =>
{
  var dt = ParseScheduledTime(dts, startRegex, endRegex);
  scheduledTimes.Add(dt);//add's items concurently into bag,
});

并行/异步/并发编程是一件很难的事情,它真的需要大量的研究,甚至超越任务,类并行,PLINQ和async/await。

请把我的建议作为进一步学习的指针,慢慢来,一步一步来,我不想阻止它,或者听起来好像不可能理解这一点,这只是一个更广泛的问题主题…

使用并行是否有性能提升?如果我正在锁定线程?

恰恰相反。因为整个代码块是由一个锁语句控制的,所以并行运行会产生开销,然后立即导致所有线程以序列化的方式运行。