关于线程池ThreadPool的学习
学习重点ThreadPool.SetMinThreads(out workerThreads, out completionPortThreads).这是整个线程池的关键。 而ThreadPool.SetMaxThreads(out workerThreads, out completionPortThreads)这个方法在你的线程总数低于1000时是不需要动它的。因为它的默认值就是1023,1000。然后在实际使用的时候只靠客户端发大量线程来处理问题是不一定能降低实际执行时间的,有时候还和服务器端、数据库有关系。
首先谈一下学习的背景,因为一箱货里有几百件产品。用一条SQL语句来检查这几百件产品是否合格,搜索数据对比规格后出结果耗费的时间在7~12秒的时间。现场的操作环境是一箱一箱货不停的扫描的。7~12秒的处理时间导致两箱货的扫描间隔达到10秒之多这是无法接受的。在这种情况下首先想到的是用多线程同时处理所有产品的数据。
List<System.Threading.Thread> list = new List<System.Threading.Thread>();
foreach (DataRow row in ds.Tables[].Rows)
{
//cellname = row[0].ToString(); System.Threading.Thread s1 = new System.Threading.Thread(QueryOCVTime);
list.Add(s1);
s1.Start(row[].ToString());
}
bool IsOver = true;
while (IsOver)
{
for (int i = ; i < list.Count; i++)
{
if (list[i].IsAlive)
{
System.Threading.Thread.Sleep();
break;
}
else if (i == (list.Count - ))
{
IsOver = false;
}
} }
代码一Thread
经过测试处理时间已经降到3~5秒了。但是离需求(1秒以内)还有很大的差距。而且也测试了单线程的执行时间才100毫秒,按逻辑来分析我几乎是同时发出所有的单线程来执行,总的执行时间应该也是100毫秒左右。所以线程都是所以就想到了线程池
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.IO;
using System.Net;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
private static List<string> list;
private static DateTime dt1;
static void Main(string[] args)
{
int maxworkthreads, maxportthreads, minworkthreads, minportthreads;
Console.WriteLine("修改前");
ThreadPool.GetMaxThreads(out maxworkthreads, out maxportthreads);
ThreadPool.GetMinThreads(out minworkthreads, out minportthreads);
Console.WriteLine(maxworkthreads.ToString() + "\t" + maxportthreads.ToString());
Console.WriteLine(minworkthreads.ToString() + "\t" + minportthreads.ToString());
//public static bool SetMinThreads(int workerThreads, int completionPortThreads);
//最关键的修改参数
//workerThreads
//这个值决定了同时执行的最大线程数,超过这个数量就要排队。
//这个值不是越大越好,要综合考虑单线程在进行什么样的操作。
ThreadPool.SetMinThreads(, minportthreads);
Console.WriteLine("修改后");
ThreadPool.GetMaxThreads(out maxworkthreads, out maxportthreads);
ThreadPool.GetMinThreads(out minworkthreads, out minportthreads);
Console.WriteLine(maxworkthreads.ToString() + "\t" + maxportthreads.ToString());
Console.WriteLine(minworkthreads.ToString() + "\t" + minportthreads.ToString());
list = new List<string>();
dt1 = DateTime.Now;
for (int i = ; i < ; i++)
{
//开始执行单线程
ThreadPool.QueueUserWorkItem(new WaitCallback(RunThread), i.ToString());
} bool IsOver = true;
while (IsOver)
{
//检测所有单线程是否执行完毕
int maxthreads, threads, workthreads;
ThreadPool.GetMaxThreads(out maxthreads, out threads);
ThreadPool.GetAvailableThreads(out workthreads, out threads);
if ((maxthreads - workthreads) == )
{
IsOver = false;
}
else
{
Thread.Sleep();
}
}
DateTime dt2 = DateTime.Now;
//运行完毕将执行过程打印出来以便于分析
for (int i = ; i < list.Count; i++)
{
Console.WriteLine(list[i]);
} Console.WriteLine("流程已经运行完毕一共耗时{0}", (dt2 - dt1).TotalSeconds.ToString("0.000")); Console.ReadKey();
}
private static void RunThread(object obj)
{ DateTime dt2 = DateTime.Now;
//假定单线程的处理时间是800毫秒
Thread.Sleep();
DateTime dt3 = DateTime.Now;
//记录下线程和执行时间的信息到后面再打印出来,以免执行时间在打印时浪费而影响测试结果
list.Add(string.Format("{0},thread {1}\t,启动时间{2},耗时 {3},总耗时 {4}",
obj.ToString(),
Thread.CurrentThread.ManagedThreadId,
(dt2 - dt1).TotalSeconds.ToString("0.000"),
(dt3 - dt2).TotalSeconds.ToString("0.000"),
(dt3 - dt1).TotalSeconds.ToString("0.000")
)
); }
}
}
ThreadPool
“public static bool SetMinThreads(int workerThreads, int completionPortThreads);”。这个SetMinThreads(out workerThreads, out completionPortThreads)方法是整个线程池的关键。WorkThreads是指最大活动线程数(即可同时执行的最大线程数),completionPortThreads是指最大IO线程数(即可同时执行的最大IO)。WorkThreads的大小影响整个流程的结束时间,如果单个线程需要10毫秒才能执行完,一共有10个线程并且把WorkThreads设置为5,那么整个流程的完成时间在20毫秒左右。即是单个线程的2倍时间。即执行时间=总线程数/WorkThreads * 单流程时间。
这段测试代码的执行结果是非常理想的。
98,thread 107 ,启动时间0.219,耗时 0.801,总耗时 1.020
99,thread 108 ,启动时间0.225,耗时 0.801,总耗时 1.026
流程已经运行完毕一共耗时1.11
但是在将这段代码移植到实际情况中时结果令人很沮丧。仍然还是要2~3秒才能出结果。仔细查看输出结果不难发现其中的问题
1,thread 6 ,启动时间0.247,耗时 0.309,总耗时 0.556
2,thread 22 ,启动时间0.270,耗时 0.291,总耗时 0.561
......
39,thread 53 ,启动时间0.372,耗时 1.389,总耗时 1.761
40,thread 55 ,启动时间0.372,耗时 1.394,总耗时 1.766
......
50,thread 61 ,启动时间0.374,耗时 1.610,总耗时 1.984
63,thread 63 ,启动时间0.373,耗时 1.677,总耗时 2.050
从上面的输出结果可以看出来在实际的使用环境中,虽然所有线程的启动时间相差是不大的,但是执行时间相差太多了从第1个线程才0.309秒到最后一个线程达到了1.677秒。表明同时执行的线程越多,到后面的线程执行的效率就越慢。导致最后的总执行时间就超出我们的预期了。
这里导致执行效率慢的原因已经不再是线程的问题了。而有可能是数据库的IO或服务器的IO有限制。客户端同时发出大量的请求查找数据,但是在服务端或者在数据库这些同时发出来的线程出现排队的情况了。这个结论是我经过大量测试后得出来的,在后期如果有条件再来验证这个想法。
关于线程池ThreadPool的学习的更多相关文章
- 对于线程池ThreadPool的学习总结
线程池:就是一个管理线程的池子. 优点: 它帮我们管理线程,避免增加创建线程和销毁线程的资源损耗.因为线程其实也是一个对象,创建一个对象,需要经过类加载过程,销毁一个对象,需要走GC垃圾回收流程,都是 ...
- java核心知识点学习----重点学习线程池ThreadPool
线程池是多线程学习中需要重点掌握的. 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互.在这种情形下,使用线程池可以很好的提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考 ...
- C#多线程学习 之 线程池[ThreadPool](转)
在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPo ...
- C#多线程学习 之 线程池[ThreadPool]
在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPo ...
- [转]C#多线程学习 之 线程池[ThreadPool]
在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPo ...
- 多线程系列 线程池ThreadPool
上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...
- 多线程系列(2)线程池ThreadPool
上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...
- 线程池ThreadPool实战
线程池ThreadPool 线程池概念 常用线程池和方法 1.测试线程类 2.newFixedThreadPool固定线程池 3.newSingleThreadExecutor单线程池 4.newCa ...
- 线程池ThreadPool的初探
一.线程池的适用范围 在日常使用多线程开发的时候,一般都构造一个Thread示例,然后调用Start使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...
随机推荐
- C#程序设计基础——字符串
C#字符串使用string关键字声明,且由一个或多个字符构成的一组字符. 串联字符串 串联字符串是将一个字符串追加到另一个字符串末尾的过程.使用“+”或“+=”运算符串链字符符文本或字符串常量.串联字 ...
- Qt如何去掉按钮等控件的虚线框(焦点框)(三种办法)
方法1:可以通过代码ui->pushButton->setFocusPolicy(Qt::NoFocus)或在Qt Creator的属性列表中设置. 方法2:如果在嵌入式设备中需要通过按键 ...
- Android Wear开发 - 数据通讯 - 第二节 : 数据的发送与接收
本节由介绍3种数据的发送接收:1.Data Items : 比特类型数据,限制100KB以内2.Assets : 资源类型数据,大小无上限3.Message : 发送消息,触发指令 http://de ...
- 一些正则在js使用方法
输入框直接正则判断 <input type="password" name="pwd" placeholder="密码只能以数字\英文\@\.& ...
- Android的TextView与Html相结合的用法
Android中的TextView,本身就支持部分的Html格式标签.这其中包括常用的字体大小颜色设置,文本链接等.使用起来也比较方便,只需要使用Html类转换一下即可.比如: textView.se ...
- JSP简易留言板
写在前面 在上篇博文JSP内置对象中介绍JSP的9个内置对象的含义和常用方法,但都是比较理论的知识.今天为大家带来一个小应用,用application制作的简易留言板. 包括三个功能模块:留言提交.留 ...
- 缓冲运动-1-[解决1].html
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8 ...
- android ContentProvider学习
1.ContentProvider提供位存储或获取数据提供了统一的接口. 2.使用ContentProvider可以在不同的应用程序之间共享数据. 3.Android为常见的一些数据提供了Conten ...
- Qt 学习之路 :Qt 线程相关类
希望上一章有关事件循环的内容还没有把你绕晕.本章将重新回到有关线程的相关内容上面来.在前面的章节我们了解了有关QThread类的简单使用.不过,Qt 提供的有关线程的类可不那么简单,否则的话我们也没必 ...
- QT unit test code coverage
准备环境: qt-creator5.2.1 , gcov(gcc 默认安装),lcov(gcov 的图形化显示界面),qt_testlib 各环境介绍: 1.gcov gcov 是一个可用于C/C ...