我最近在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
有一个改进,但 - 当然不会与线程的增加接近线性。我怀疑有一个明确的解释 - 但我想分享代码,因为有几个人花时间回应。感谢。
答案 0 :(得分:1)
线程不是免费的,它们有使用开销。每个线程的工作越少,工作与开销的比率就越大。
此外,除非您的系统有8个核心,其核心数多于核心数,否则不会产生任何真正的好处。