【问题标题】:Un-Threaded is faster than threaded非线程比线程快
【发布时间】:2013-10-15 06:20:11
【问题描述】:

我有一个应用程序需要在应用程序启动时读取非常大的.CSV 文件并将每一行转换为object。这些是读取文件的方法:

public List<Aobject> GetAobject()
    {
        List<Aobject> Aobjects = new List<Aobject>();

        using (StreamReader sr = new StreamReader(pathA, Encoding.GetEncoding("Windows-1255")))
        {
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                string[] spl = line.Split(',');
                Aobject p = new Aobject { Aprop = spl[0].Trim(), Bprop = spl[1].Trim(), Cprop = spl[2].Trim() };
                Aobjects.Add(p);
            }
        }

        return Aobjects;
    }

    public List<Bobject> GetBobject()
    {
        List<Bobject> Bobjects = new List<Bobject>();

        using (StreamReader sr =
           new StreamReader(pathB, Encoding.GetEncoding("Windows-1255")))
        {
            //parts.Clear();
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                string[] spl = line.Split(',');
                Bobject p = new Bobject();
                p.Cat = spl[0];
                p.Name = spl[1];
                p.Serial1 = spl[3].ToUpper().Contains("1");
                if (spl[4].StartsWith("1"))
                    p.Technical = 1;
                else if (spl[4].StartsWith("2"))
                    p.Technical = 2;
                else
                    p.Technical = 0;
                Bobjects.Add(p);
            }
        }

        return Bobjects;
    }

这阻止了我的UI 几秒钟,所以我试着让它成为multi-Threaded。但是我所有的测试都表明un-threaded 场景更快。这就是我测试它的方式:

 Stopwatch sw = new Stopwatch();
            sw.Start();

            for (int i = 0; i < 1000; i++)
            {
                Dal dal = new Dal();
                Thread a = new Thread(() => { ThreadedAobjects = dal.GetAobject(); });
                Thread b = new Thread(() => { ThreadedBobjects = dal.GetBobject(); });

                a.Start();
                b.Start();

                b.Join();
                a.Join();
            }
            sw.Stop();

            txtThreaded.Text = sw.Elapsed.ToString();

            Stopwatch sw2 = new Stopwatch();
            sw2.Start();

            for (int i = 0; i < 1000; i++)
            {
                Dal dal2 = new Dal();
                NonThreadedAobjects = dal2.GetAobject();
                NonThreadedBobjects = dal2.GetBobject();
            }
            sw2.Stop();

            txtUnThreaded.Text = sw2.Elapsed.ToString();

结果:
线程运行:00:01:55.1378686
非线程运行:00:01:37.1197840
.Net4.0 编译,但也应在.Net3.5 下工作,处于发布模式。
有人可以解释一下为什么会发生这种情况,我该如何改进?

【问题讨论】:

  • 创建线程需要时间。您总是创建一个新线程而不是重用现有线程(线程池)。
  • 通常的线程答案适用;创建线程很昂贵。您可以尝试改用 ThreadPool。你也在做并行 IO 工作,检查你的硬盘请求队列长度,看看它们是否排队或缓存。您总是可以(前方有疯狂的想法!)使用 cpu 分析器来衡量什么是缓慢的。
  • 另外,你的硬件是什么?这两个文件是在相同的驱动器上还是不同的驱动器上?你有一个或几个cpu核心吗?目标是使其加载更快,还是确保 ui 不会锁定?
  • 您每次运行都测量了什么?挂钟时间? CPU 时间?

标签: c# multithreading performance


【解决方案1】:

您忽略了与创建和启动线程相关的成本。尝试使用线程池,而不是创建新线程:

ThreadPool.QueueUserWorkItem(() => { ThreadedAobjects = dal.GetAobject(); });

您还需要记录已完成的操作次数,以便正确计算总时间。看看这个链接:http://msdn.microsoft.com/en-us/library/3dasc8as.aspx

【讨论】:

  • 谢谢,您能否建议一种有效的方法来等待ThreadPool 完成?
  • @Yoav 链接中显示的手动重置事件模式非常有效,尽管不是很解耦。
【解决方案2】:

我建议使用单个线程调用GetAobject,然后调用GetBobject。您的任务几乎肯定是 I/O 绑定的,如果这两个文件非常大并且在同一个驱动器上,那么尝试同时访问它们将导致大量不必要的磁盘查找。所以你的代码变成了:

ThreadPool.QueueUserWorkItem(() =>
{
    AObjects = GetAObject();
    BObjects = GetBObject();
});

这也简化了您的代码,因为您只需同步一个ManualResetEvent

【讨论】:

    【解决方案3】:

    如果你运行这个测试,你每次都会得到稍微不同的结果。事情发生所花费的时间受到计算机运行时发生的许多事情的影响 - 例如:其他进程、GC 等。

    但是您的结果是合理的,因为拥有另一个线程意味着处理器需要更多的上下文切换,并且每次上下文切换都需要时间......

    您可以阅读有关上下文切换的更多信息: http://en.wikipedia.org/wiki/Context_switch

    【讨论】:

      【解决方案4】:

      添加到 Slugart 的正确答案:您的并行化在许多方面都无效,因为您等待第一个线程完成,而第二个线程可能会更快完成并且一段时间内什么都不做(查看任务并行库和 PLINQ) .

      此外,您的操作受 IO 限制,这意味着并行性取决于 IO 设备(某些设备以顺序方式执行更好,尝试进行多次读取会减慢整体操作)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-09
        • 1970-01-01
        • 2015-08-22
        • 1970-01-01
        • 2021-08-07
        • 2013-11-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多