学习重点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的学习的更多相关文章

  1. 对于线程池ThreadPool的学习总结

    线程池:就是一个管理线程的池子. 优点: 它帮我们管理线程,避免增加创建线程和销毁线程的资源损耗.因为线程其实也是一个对象,创建一个对象,需要经过类加载过程,销毁一个对象,需要走GC垃圾回收流程,都是 ...

  2. java核心知识点学习----重点学习线程池ThreadPool

    线程池是多线程学习中需要重点掌握的. 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互.在这种情形下,使用线程池可以很好的提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考 ...

  3. C#多线程学习 之 线程池[ThreadPool](转)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  4. C#多线程学习 之 线程池[ThreadPool]

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  5. [转]C#多线程学习 之 线程池[ThreadPool]

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  6. 多线程系列 线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

  7. 多线程系列(2)线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

  8. 线程池ThreadPool实战

    线程池ThreadPool 线程池概念 常用线程池和方法 1.测试线程类 2.newFixedThreadPool固定线程池 3.newSingleThreadExecutor单线程池 4.newCa ...

  9. 线程池ThreadPool的初探

    一.线程池的适用范围 在日常使用多线程开发的时候,一般都构造一个Thread示例,然后调用Start使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...

随机推荐

  1. 以Facebook为案例剖析科技公司应有的工具文化

    http://www.36kr.com/p/146507.html 编者按:本文由 @王淮Harry哥 撰写,摘自他即将出版的新书.王淮是 Facebook 早期员工,中国藉第二位工程师第一位研发经理 ...

  2. Sublime Text 3 配置

    配置: { "font_face": "Source Code Pro", , "highlight_line": true, " ...

  3. OpenSSH远程拒绝服务漏洞

    漏洞版本: OpenSSH 漏洞描述: Bugtraq ID:61286 OpenSSH是一种开放源码的SSH协议的实现 OpenSSH存在一个安全漏洞,允许远程攻击者利用漏洞提交恶意请求,使应用程序 ...

  4. 数据结构(线段树):CodeForces 145E Lucky Queries

    E. Lucky Queries time limit per test 3 seconds memory limit per test 256 megabytes input standard in ...

  5. Android Json数据解析

    1.通过主Activity的Button按钮进行解析 public class MainActivity extends Activity { private Button button=null; ...

  6. Using Apache Web Server with Jboss AS 7

    In real-world projects, it's common to find Apache web server as a front door to your application se ...

  7. 如何从硬盘安装fedora 19 (How to install fedora 19 from hard drive, Fedora-19-i386-DVD.iso)

    现在fedora 19出来了, 它的安装界面与跟fedora 18相同,都是metro UI. 不过现在官方已经不再推荐下载i386,而是x86-64位了,是不是现在x86-64已经把兼容性做得很好了 ...

  8. mysql编码和Java编码相应一览表

    MySQL to Java Encoding Name Translations MySQL Character Set Name Java-Style Character Encoding Name ...

  9. 算法9-5:最大流算法的Java代码

    残留网络 在介绍最大流算法之前先介绍一下什么是残留网络.残余网络的概念有点类似于集合中的补集概念. 下图是残余网络的样例. 上面的网络是原始网络.以下的网络是计算出的残留网络.残留网络的作用就是用来描 ...

  10. 关于Yaffs2在u-boot中的支持

    开发板是一块2G的MLC的NandFlash,页大小8k+512,为其移植u-boot到yaffs2这了.以前在Mini2440上移植过2k+64的slc的NandFlash的Yaffs2支持,当然也 ...