并发访问静态TryParse方法

时间:2017-11-22 00:24:07

标签: c# .net multithreading

我最近在C#中编写了一个平面文件数据分析器 - 部分原因只是一个有趣的项目。探查器使用各种C#TryParse方法来确定数据类型。

性能很差,因此我尝试了一些不同的多线程方法。 (我在Studio中运行了性能分析器,它指出解析是CPU时间的主要部分。)

我没有从线程中看到太多改进,因此我在网上找到了.Net代码(referencesource.microsoft.com)。各种解析方法都是静态的,并且看起来以非线程安全的方式运行。

然而,线程代码产生了正确的结果。我没有看到任何在.Net代码中表示线程同步的属性。这让我想知道是否有一些同步机制,.Net正在强制执行,我无法直接在代码中看到。

有人知道.Net运行时是否可能以某种方式同步对静态解析方法的访问?这可以解释

a)通过并发访问静态方法和

来获得正确的结果

b)没有真正的性能提升,因为静态是一个瓶颈。

我只是感到困惑。

更新于11月32日 - 这是一个精简版本,用于说明:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace parse
{
    class Program
    {
        static void Main(string[] args)
        {
            int totalParseCount = 50000000;
            int maxThreads = 8;

            Console.WriteLine("TryParse\n--------");
            for (int threads = 1; threads <= maxThreads; ++threads)
            {
                List<Task> tasks = new List<Task>();
                DateTime start = DateTime.Now;
                Console.WriteLine(string.Format("Thread count: {0}", threads));
                for (int i = 0; i < threads; ++i)
                {
                    tasks.Add(Task.Run(() =>
                    {
                        int threadParseCount = 0;
                        while (threadParseCount < totalParseCount / threads)
                        {
                            int intOut;
                            long longOut;
                            DateTime dtOut;
                            decimal decOut;
                            int.TryParse("1b12i341i24b1234bo123", out intOut);
                            long.TryParse("1b12i341i24b1234bo123", out longOut);
                            DateTime.TryParse("1b12i341i24b1234bo123", out dtOut);
                            decimal.TryParse("1b12i341i24b1234bo123", out decOut);
                            ++threadParseCount;
                        }
                        Console.WriteLine(string.Format("  Thread: {0}; Parse ops: {1}", Thread.CurrentThread.ManagedThreadId, threadParseCount));
                    }));
                }
                Task.WaitAll(tasks.ToArray());
                Console.WriteLine(string.Format("Elapsed (HH:MM:SS.Milli): {0}", DateTime.Now - start));
            }
        }
    }
}

...这是我系统上的输出(4个双核):

TryParse
--------
Thread count: 1
  Thread: 3; Parse ops: 50000000
Elapsed (HH:MM:SS.Milli): 00:01:31.8389593
Thread count: 2
  Thread: 4; Parse ops: 25000000
  Thread: 3; Parse ops: 25000000
Elapsed (HH:MM:SS.Milli): 00:00:58.8212779
Thread count: 3
  Thread: 3; Parse ops: 16666666
  Thread: 4; Parse ops: 16666666
  Thread: 6; Parse ops: 16666666
Elapsed (HH:MM:SS.Milli): 00:00:47.8153264
Thread count: 4
  Thread: 6; Parse ops: 12500000
  Thread: 5; Parse ops: 12500000
  Thread: 4; Parse ops: 12500000
  Thread: 3; Parse ops: 12500000
Elapsed (HH:MM:SS.Milli): 00:00:42.6872096
Thread count: 5
  Thread: 5; Parse ops: 10000000
  Thread: 6; Parse ops: 10000000
  Thread: 3; Parse ops: 10000000
  Thread: 7; Parse ops: 10000000
  Thread: 4; Parse ops: 10000000
Elapsed (HH:MM:SS.Milli): 00:00:44.5965817
Thread count: 6
  Thread: 5; Parse ops: 8333333
  Thread: 6; Parse ops: 8333333
  Thread: 4; Parse ops: 8333333
  Thread: 8; Parse ops: 8333333
  Thread: 3; Parse ops: 8333333
  Thread: 7; Parse ops: 8333333
Elapsed (HH:MM:SS.Milli): 00:00:41.9454271
Thread count: 7
  Thread: 9; Parse ops: 7142857
  Thread: 5; Parse ops: 7142857
  Thread: 6; Parse ops: 7142857
  Thread: 7; Parse ops: 7142857
  Thread: 4; Parse ops: 7142857
  Thread: 3; Parse ops: 7142857
  Thread: 8; Parse ops: 7142857
Elapsed (HH:MM:SS.Milli): 00:00:40.8728885
Thread count: 8
  Thread: 10; Parse ops: 6250000
  Thread: 5; Parse ops: 6250000
  Thread: 9; Parse ops: 6250000
  Thread: 7; Parse ops: 6250000
  Thread: 6; Parse ops: 6250000
  Thread: 4; Parse ops: 6250000
  Thread: 8; Parse ops: 6250000
  Thread: 3; Parse ops: 6250000
Elapsed (HH:MM:SS.Milli): 00:00:37.8051313

有一个改进,但 - 当然不会与线程的增加接近线性。我怀疑有一个明确的解释 - 但我想分享代码,因为有几个人花时间回应。感谢。

1 个答案:

答案 0 :(得分:1)

线程不是免费的,它们有使用开销。每个线程的工作越少,工作与开销的比率就越大。

此外,除非您的系统有8个核心,其核心数多于核心数,否则不会产生任何真正的好处。