多线程实例(二)——遍历文件夹分割文件识别文件内容
2020-12-25 00:28
标签:alt 最大 创建 系统 second nal sleep close 接下来 上篇写完,感觉作为一个程序员,没有撸到底好像有点不过瘾对不对?大家都知道,C#早已进阶到8.0时代了,还用原始的Thread来写感觉有点low呀,而且通篇到最后居然还有线程最大值限制,技术控不能忍!!! 那么本篇就干脆继续优化,理想状态是8秒,我就必须将整个过程压缩到8秒这个量级!而且尽量使用新技术。 1.引入线程池ThreadPool,来控制线程数,提高效率。 2.引入CountdownEvent同步基元,通过它的信号计数来确定多线程是否成功完成。 如何获取线程池能够使用的最大线程数和最小线程数呢? 根据操作系统和CPU硬件不同,得到的值也有所不同,我们这里需要先记录下来这几个阈值,后面优化时需要用到。 接下来,我们可以对比一下使用线程池和使用线程的性能。 此例可以看出线程池反复利用10~15这几个线程,大量节约了创建线程,切换上下文等的时间消耗。 OK,既然验证有效,我们不妨开始按照预先的构思,开始编码吧! 可惜,执行结果居然耗时32秒多。 分析:我们的代码有两个地方都用到了线程池,第一个地方是想要同步切割原始文件时,第二个地方是每次识别切割文件时,就需要从线程池分配一个线程去识别,因为识别耗时较长。 从这里的输出来看,①231ms和232ms,②239ms和247ms,③759ms和780ms,④1199ms和1199ms,似乎同时只有两个线程在并发执行,推断应该是线程池的最小线程数(nMinThread=2)在起作用,也就是说,当任务数量大于最小线程数时,线程池每次就新创建(nMinThread=2)个线程,各自领取一个任务去做,其余的任务则继续在线程池里等待(当前面这两个线程任务完成重新空闲时,才会领取后面的任务去做),导致了耗时。 结论:通过设置线程池的最小线程数(nMinThread=2),可以提高并发执行数,提高效率。 要达到最快的话,9个文件的分割需要9个线程,每个原始文件分割为6个子文件,所以需要识别的文件为6*9=54个文件,每次识别需要1个线程,总共则需要63个线程,这明显也小于系统1000的阈值限制,可以放心设置,使任务不再处于等待状态。 最终结果: 执行结果耗时8秒多,达到了预期。 多线程实例(二)——遍历文件夹分割文件识别文件内容 标签:alt 最大 创建 系统 second nal sleep close 接下来 原文地址:https://www.cnblogs.com/chaoyazhisi/p/13208659.html 1 static void Main(string[] args)
2 {
3 ThreadPool.GetMaxThreads(out nMaxThread, out nMaxThread_IO);
4 strInfo = $"nMaxThread : {nMaxThread}, nMaxThread_async : {nMaxThread_IO}.";
5 Console.WriteLine(strInfo);
6 ThreadPool.GetMinThreads(out nMinThread, out nMinThread_IO);
7 strInfo = $"nMinThread : {nMinThread}, nMinThread_async : {nMinThread_IO}.";
8 Console.WriteLine(strInfo);
9 Console.ReadKey();
10 }
1 class Program
2 {
3 private static readonly Stopwatch sw = new Stopwatch();
4 private static string strInfo;
5
6 static void Main(string[] args)
7 {
8 sw.Start();
9 strInfo = $"Enter Main : {sw.ElapsedMilliseconds} ms";
10 Console.WriteLine(strInfo);
11 const int numberOfThreads = 300;
12 sw.Reset();
13 sw.Start();
14 UseThreadPool(numberOfThreads);
15 sw.Stop();
16 Console.WriteLine("Execution time using threadpool: {0}", sw.ElapsedMilliseconds);
17
18 sw.Reset();
19 sw.Start();
20 UseThreads(numberOfThreads);
21 sw.Stop();
22 Console.WriteLine("Execution time using threads: {0}", sw.ElapsedMilliseconds);
23 Console.ReadKey();
24 }
25
26 static void UseThreads(int numberOfThreads)
27 {
28 using (var countdown = new CountdownEvent(numberOfThreads))
29 {
30 Console.WriteLine("Scheduling work by creating threads");
31 for (int i = 0; i )
32 {
33 var thread = new Thread(() => {
34 Thread.Sleep(TimeSpan.FromSeconds(0.1));
35 Console.Write("{0} ", Thread.CurrentThread.ManagedThreadId);
36 countdown.Signal();
37 });
38 thread.Start();
39 }
40 countdown.Wait();
41 Console.WriteLine();
42 }
43 }
44
45 static void UseThreadPool(int numberOfThreads)
46 {
47 using (var countdown = new CountdownEvent(numberOfThreads))
48 {
49 Console.WriteLine("Starting work on a threadpool");
50 for (int i = 0; i )
51 {
52 ThreadPool.QueueUserWorkItem(_ => {
53 Thread.Sleep(TimeSpan.FromSeconds(0.1));
54 Console.Write("{0} ", Thread.CurrentThread.ManagedThreadId);
55 countdown.Signal();
56 });
57 }
58 countdown.Wait();
59 Console.WriteLine();
60 }
61 }
62 }
1 class Program
2 {
3 private static readonly Stopwatch sw = new Stopwatch();
4 private static string strInfo;
5
6 static void Main(string[] args)
7 {
8 sw.Start();
9 strInfo = $"Enter Main : {sw.ElapsedMilliseconds} ms";
10 Console.WriteLine(strInfo);
11
12 string strFilefolder = "";
13 OcrProcess(strFilefolder);
14 strInfo = $"Main Completed : {sw.ElapsedMilliseconds} ms";
15 Console.WriteLine(strInfo);
16 sw.Stop();
17 Console.ReadKey();
18 }
19
20 static void OcrProcess(string strFilefolder)
21 {
22 Liststring> list_sourcefile = GetFileList(strFilefolder);
23 using (var countdown = new CountdownEvent(list_sourcefile.Count))
24 {
25 list_sourcefile.ForEach((sourcefile) =>
26 {
27 ThreadPool.QueueUserWorkItem(_ =>
28 {
29 strInfo = $"{sourcefile} : {sw.ElapsedMilliseconds} ms";
30 Console.WriteLine(strInfo);
31 //这里对文件进行分割
32 SplitProcess(sourcefile);
33 countdown.Signal();
34 });
35 });
36 countdown.Wait();
37 }
38 }
39
40 static void SplitProcess(string sourcefile)
41 {
42 strInfo = $"{sourcefile} Split Start : {sw.ElapsedMilliseconds} ms";
43 Console.WriteLine(strInfo);
44 int nSplitNum = 6;
45 using (var countdown = new CountdownEvent(nSplitNum))
46 {
47 for (int i = 0; i )
48 {
49 //模拟分割单个文件的过程,花费500ms
50 Thread.Sleep(500);
51 string split_file = sourcefile + i;
52 strInfo = $"{split_file} Ready : {sw.ElapsedMilliseconds} ms";
53 Console.WriteLine(strInfo);
54 ThreadPool.QueueUserWorkItem(_ =>
55 {
56 RecognizeProcess(split_file);
57 countdown.Signal();
58 });
59 }
60 countdown.Wait();
61 }
62 strInfo = $"{sourcefile} Split Completed : {sw.ElapsedMilliseconds} ms";
63 Console.WriteLine(strInfo);
64 }
65
66 static void RecognizeProcess(string split_file)
67 {
68 //模拟识别的过程,花费5000ms
69 Thread.Sleep(5000);
70 strInfo = $"{split_file} OCR completed : {sw.ElapsedMilliseconds} ms";
71 Console.WriteLine(strInfo);
72 }
73
74 static Liststring> GetFileList(string strFilefolder)
75 {
76 Liststring> list_file = new Liststring>();
77 for (int i = 0; i 2; i++)
78 {
79 for (int j = 0; j 2; j++)
80 list_file.Add("File" + i + j);
81 }
82 return list_file;
83 }
84
85 }
1 ThreadPool.SetMinThreads(63, 63);
文章标题:多线程实例(二)——遍历文件夹分割文件识别文件内容
文章链接:http://soscw.com/index.php/essay/38039.html