C#线程池用法
C#线程池用法
在C#编程语言中,使用线程池可以并行地处理工作,当强制线程和更新进度条时,会使用内建架构的ThreadPool类,为批处理使用多核结构,这里我们来看在C#编程语言中一些关于来自System.Threading的ThreadPool的用法的例子。
介绍
.NET Framework提供了包含ThreadPool类的System.Threading 空间,这是一个可直接访问的静态类,该类对线程池是必不可少的。它是公共“线程池”设计样式的实现。对于后台运行许多各不相同的任务是有用的。对于单个的后台线种而言有更好的选项。
线程的最大数量。这是完全无须知道的。在.NET中ThreadPool的所有要点是它自己在内部管理线程池中线程。多核机器将比以往的机器有更多的线程。微软如此陈述“线程池通常有一个线程的最大数量,如果所有的线程都忙,增加的任务被放置在队列中直到它们能被服务,才能作为可用的线程。”
用法位置
线程池类型能被用于服务器和批处理应用程序中,线程池有更廉价的得到线程的内部逻辑,因为当需要时这些线程已被形成和刚好“连接”,所以线程池风格代码被用在服务器上。
MSDN表述:“线程池经常用在服务器应用程序中,每一个新进来的需求被分配给一个线程池中的线程,这样该需求能被异步的执行,没有阻碍主线程或推迟后继需求的处理。”
ThreadPool VS BackgroundWorker
如果你正在使用Windows窗体,宁可使用BackgroundWorker来对付那些更简单的线程需求,BackgroundWorker在网络访问和其他一些简单的事情方面做得很好。但对于多处理器的批处理来说,你需要ThreadPool。
当你的程序要批处理时,考虑线程池
当你的程序产生很多(3个以上)线程时,考虑线程池
当你的程序使用Windows窗体时,考虑后台执行。
线程要考虑的事 同样,如何使用线程的细节能帮助发现最好的代码。下面比较线程情形和哪个类是最好的。
你需要一个额外的线程 使用后台执行
你有许多短期的线程 使用线程池
需求
线程很重要,但对于那些不会花很长时间来执行且只做一件事情的大多数应用程序来说却并不重要的。线程对于界面可用性不是很重要的的应用程序而言也不是很重要,要尽量避免使用线程(译者注:比如进度条不是很重要的应用程序)。
连接方法
可使用QueueUserWorkItem连接方法(methods)到线程池。方法要运行在线程上,则必须把它连接到QueueUserWorkItem。如何实现呢?必须使用WaitCallback。在MSDN中,WaitCallback被描述成当线程池执行时要被调用的委托回调方法,是回调它的参数的委托。
WaitCallback
只需指定“new WaitCallback”语句作为ThreadPool.QueueUserWorkItem的第一个参数来使用WaitCallback.不需要任何其他的代码来使用这方法生效。
使用WaitCallback的例子
void Example() { // 连接 ProcessFile 方法到线程池. //注意: 'a' 是一个作为参数的对象 ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), a); } private void ProcessFile(object a) { // 我被连接到线程池通过 WaitCallback. }
参数
我们能通过定义一个特定的类并把一些重要的值放在类里面来使用参数,那么,方法接收了对象,就能通过对象向方法传递多个参数了。以下是一个早期的例子。
使用带参数QueueUserWorkItem 的例子
//指定作为线程池方法的参数的类 class ThreadInfo { public string FileName { get; set; } public int SelectedIndex { get; set; } } class Example { public Example() { // 声明一个新的参数对象 ThreadInfo threadInfo = new ThreadInfo(); threadInfo.FileName = "file.txt"; threadInfo.SelectedIndex = 3; //发送自定义的对象到线程方法 ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), threadInfo); } private void ProcessFile(object a) { ThreadInfo threadInfo = a as ThreadInfo; string fileName = threadInfo.FileName; int index = thread.SelectedIndex; } }
发生了什么事?我们发送两个值给这个线程化的ProcessFile方法,它需要知道文件名和选择索引,而我们在这个对象中把参数都发送了给它。
进度条
能通过从设计器中右边的工具盒面板中增加Windows窗体控件到你的窗体程序来使用进度条并设置 progressBar1.Value, progressBar1.Minimum 和progressBar1.Maximum。 progressBar1.Value是最小值和最大值中间的位置,以下代码用来初始化进度条:
设置进度条的例子
//设置进度条的长度. // 这里我们有6个单位来完成,所以6是最大值。 // 最小值通常是0 progressBar1.Maximum = 6; // 或其他数字 progressBar1.Minimum = 0;
进度条位置 你的进度条中的有颜色部分是当前值与最大值的百分比。所以,如果最大值是6,而值是3即表示做完了一半。
ProgressBar 例子 (Windows Forms)
在进度条中调用Invoke(援引)
让我们看如何在进度条实例中使用Invoke方法。遗憾的是,你不能在辅助线程中访问Windows控件,因为UI线程是分离的,必须使用委托(delegate)和Invoke到进度条。
请求Invoke(调用)的例子
public partial class MainWindow : Form { // 这是运行在UI线程来更新条的委托 public delegate void BarDelegate(); //该窗体的构造器(由Visual Studio自己产生) public MainWindow() { InitializeComponent(); } //当按下按钮,启动一个新的线程 private void button_Click(object sender, EventArgs e) { // 设定进度条的长度. progressBar1.Maximum = 6; progressBar1.Minimum = 0; // 给线程传递这些值. ThreadInfo threadInfo = new ThreadInfo(); threadInfo.FileName = "file.txt"; threadInfo.SelectedIndex = 3; ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), threadInfo); } // 运行在后台线程上的东西 private void ProcessFile(object a) { // (省略) // 使用'a'做一些重要的事. // 告诉UI 我们已经完成了. try { // 在窗体中调用委托 . this.Invoke(new BarDelegate(UpdateBar)); } catch { //当一些问题发生后我们能使程序恢复正常 } } //更新进度条. private void UpdateBar() { progressBar1.Value++; if (progressBar1.Value == progressBar1.Maximum) { // 结束了,进度条满了. } } }
委托语法 以上代码的开始处,可以看到声明 UpdateBar 的委托。它告诉Visual Studio 和C# 需要来使用这个作为对象的方法。
更多需要的工作 以上程序演示了如何设定进度条的最大值和最小值,如何在工作完成后“Invoke”委托方法来增加进度条的大小。
在调试器中的线程
这儿要显示如何在Visual Studio的调试器中查看线程。一旦你有一个运行的程序,你能采取这些措施来可视化你的线程。首先,以调试模式打开你的线程应用程序,一旦你的应用程序运行在调试器,告知它去做它的工作而且运行这些线程,通过绿色箭头运行调试器,当线程正在运行,在工具条中单击“pause"按钮。
下一步 调试>窗口>线程.该菜单项将打开一个类似下图的窗口,你能看见有多少线程正在线程池中运行。
四个辅助线程 上图显示了共有10个线程,但只有四个辅助线程(Worker Thread)在程序中被分配给MainWindow.ProcessFile.
约束辅助线程
如果你有一个双核或四核系统,你将考虑最多两个四个很费力的线程。我们能在运行的线程中保持一个_threadCount 字段并且跟踪它的数值。用这个线程计数字段,你将需要在C#语言中使用一个锁来避免造成这个字段读和写的错误,锁保护你的线程被其他线程所改变。
计数线程的例子
// 锁住这个对象. readonly object _countLock = new object(); private void ProcessFile(object argument) { // 约束辅助线程的数量 while (true) { lock (_countLock) { if (_threadCount < 4) { // Start the processing _threadCount++; break; } } Thread.Sleep(50); } // Do work... }
我们看到什么 以是代码是异步执行的方法。只有其他辅助线程少于4个时它才会工作。这对于一个四核机器是好的。请看描述锁声明的更多上下文的文章
控制线程计数器
你可以在ThreadPool上使用SetMinThreads 来在连发活动中提高吞吐量和性能。以下是关于可使用的最佳的最小线程数量的材料。
ThreadPool.SetMinThreads Method
总结
我们了解了如何在C#程序中使用线程池来有效管理多个线程,在Windows 窗体应用程序的进度条和用户界面中能给人留很深印象并且也不难实现。然而,线程带来了很多的复杂性并导致漏洞,线程池是一个有用的简化,但它仍然是困难的。
unix/linux中图形界面那些事
我们知道unix/linux刚开始的时候是没有图形界面的,随着时代的发展,排版、制图、多媒体应用越来越普遍了,这些需求都需要用到图形界面(Graphical User Interface)。为此,MIT在1984年开发出了X window system,X在字母表中是W(indows)的下一个字母,寓意“下一代GUI”的意思。目前为止,unix/linux上几乎所有的发行版都采用X window system来作为自己的图形界面,它已经成为事实上的unix/linux图形界面标准。
X window system,又名X,X11(现在主要的X window system大都基于其第11个版本),是一个能够跨网络和操作系统平台的图形界面。开发者在开发x时就希望,这个窗口界面不要与硬件有强烈的相关性,这是因为如果与硬件的相关性高,那就等于开发一个操作系统了,如此一来其应用性就要受到限制。故此,x是一套软件体系,而不是操作系统中的组成部分,就像浏览器不是操作系统的组成部分一样(当然微软在与网景干仗时可不管这些)。
X的软件架构
如上图所示,X使用服务器-客户端模型:每个需要显示图形界面的主机都要运行一个x server,它负责主机中各个与图形界面有关硬件设备的管理,如在显示器中显示输出,从鼠标、键盘接受输入等。同时与不同的客户端程序(x client)通信,x client指那些需要图形界面的应用程序,如浏览器、终端、视频播放器等。这里需要解释一下,这里的server,client术语是从应用的角度而不是以用户的角度来说的:X server利用自己对硬件的掌控为应用提供显示界面以及处理输入输出等服务,所以说它是服务器端,而各种应用需要使用x server提供的这些服务,他们就是客户端了。
x server和x client之间所使用的通信协议对网络来说是透明的,所以client和server可以运行在相同机器上,也可以运行在不同机器上,甚至机器本身的硬件架构和操作系统也可以不一样(如windows上的xmanager就是一个x server,它可以远程连接linux上的主机为linux上的x client提供服务,有兴趣的童鞋可以试下)。
说完了x的软件架构,下面我们就来说说x中其他几个概念。
1. X Display Manager(XDM)
display manager,又称login manager,是linux在boot进程完成之后启动的一个用于用户身份认证的图形界面,相当于文本模式下启动时让我们输入用户名和密码的shell。比较常见的有GNOME的gdm,KDE的kdm等。
display manager可以在本地也可以在远程主机上启动。如果在本地启动,display manager接下来会把x server也启动起来,这样就可以在开机时显示如上图所示的图形界面了。
如果display manager已经在远程启动了,我们在本地需要连接到远程的display manager上去,这时x server就用使用XDMCP(X Display Manager Control Protocol)协议连接到远程的display manager,请求开启一个会话,这样在本地也就出现了如上图所示画面,如果身份认证通过,display manager就退居二线,剩下的就是本地的x server与远程的x client之间互相交流了:我们通过x server(键盘、鼠标等输入设备)把我们的要求发给x client(x client与display manager 运行在同一台机器上),x client运行得到结果并将结果返回给x server,x server再通过自己管理的输出设备如显示屏等把结果显示出来,如此种种可以参看下图。
2. GNOME,KDE......
3. GNOME与X的区别与联系
关于GNOME与X之间的关系,这里有一篇文章介绍的非常清楚,现摘抄一部分如下,我就不画蛇添足了:
X11 is the window system. Gnome is a desktop environment. The difference is that Gnome works through X11. Gnome and X11 run on Linux, though, not Windows.
Basically, X11 is what displays everything. It's the graphical shell that connects you to the operating system. None of the applications you run ever send anything directly to the screen - they need to tell X11 what they want to display and let it do the work for them.
X11 draws and moves windows and responds to input from the keyboard and mouse. That's pretty much it. Everything else is taken care of by the desktop environment. What that means is that the look and feel of the windows and the way those windows behave are all decided by which desktop environment you're using (Gnome, KDE, XFCE, etc.).
The desktop environments all have their own graphics libraries (reusable chunks of code) that they use, along with APIs (Application Programming Interfaces) which allow programmers to use those libraries when they create GUI applications. This way programmers don't have to recreate commonly used functions and elements from scratch, and the whole operating system has a more standardized look.
参考链接:http://en.wikipedia.org/wiki/X_Window_System
http://en.wikipedia.org/wiki/X_display_manager_(program_type)
https://wiki.archlinux.org/index.php/Display_Manager
https://wiki.debian.org/DisplayManager
http://en.wikipedia.org/wiki/GNOME
http://stackoverflow.com/questions/17251293/what-is-the-relationship-between-x11-and-gnome
C#线程池用法的更多相关文章
- 四种Java线程池用法解析
本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 http://www.jb51.net/article/81843.htm 1.new Thread的弊端 执行一个异步任务你还只是如下 ...
- 【java】之常用四大线程池用法以及ThreadPoolExecutor详解
为什么用线程池? 1.创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处-理效率2.线程并发数量过多,抢占系统资源从而导致阻塞3.对线程进行一些简单的管理 在Java中,线程池 ...
- Java常用四大线程池用法以及ThreadPoolExecutor详解
为什么用线程池? 1.创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处-理效率 2.线程并发数量过多,抢占系统资源从而导致阻塞 3.对线程进行一些简单的管理 在Java中,线 ...
- java 线程池用法
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, ...
- 面试题:四种Java线程池用法解析 !=!=未看
1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? 1 2 3 4 5 6 7 8 new Thread(new Runnable() { @Override ...
- Spring Boot系列二 Spring @Async异步线程池用法总结
1. TaskExecutor Spring异步线程池的接口类,其实质是java.util.concurrent.Executor Spring 已经实现的异常线程池: 1. SimpleAsyncT ...
- Java多线程-新特性-线程池
Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序 ...
- Python3-进程池与线程池
进程池与线程池 在刚开始学多进程或多线程时,我们迫不及待地基于多进程或多线程实现并发的套接字通信,然而这种实现方式的致命缺陷是:服务的开启的进程数或线程数都会随着并发的客户端数目地增多而增多,这会对服 ...
- Android 多线程: 完全解析线程池ThreadPool原理&使用
目录 1. 简介 2. 工作原理 2.1 核心参数 线程池中有6个核心参数,具体如下 上述6个参数的配置 决定了 线程池的功能,具体设置时机 = 创建 线程池类对象时 传入 ThreadPoolExe ...
随机推荐
- C++语言债券系列之十一——友元函数和拷贝构造函数
1.好友功能 (1)友元函数类的普通功能外定义. 定义友元函数和相同的正常功能.在类必须声明的正常功能为好友. (2)友元函数不是一个成员函数. 你不能反对打电话.但直接调用:友元函数访问类的公共.p ...
- hdu 1098 Ignatius's puzz
有关数论方面的题要仔细阅读,分析公式. Problem Description Ignatius is poor at math,he falls across a puzzle problem,so ...
- oracle_修改Oracle数据库字符集 AL32UTF8;
修改数据库字符集 以支持维文等 utf8 停掉库 进入装载模式 ALTER SYSTEM ENABLE RESTRICTED SESSION; ALTER SYSTEM SET JOB_QUEUE_ ...
- SpringMVC1
itRed You are never too old to set another goal or to dream a new dream. SpringMVC一路总结(一) SpringMVC听 ...
- java_tomcat_Server at localhost was unable to start within 45 seconds 小喵咪死活启动报错-二
错误:Server Tomcat v6.0 Server at localhost was unable to start within 45 seconds 错误提示就是我们限定了部署的时间导致的错 ...
- Eclipse 引导阮卓项目 No projects are found to import解
我们指示import当项目.由于一些git项目不.project和.classpath档.因此,直接import当然不是现有项目. 下面是解决方式: 1. new Android Project里面换 ...
- JDBC加载过程
jdbc载入的过程如图所看到的. 桥接模式请參照:设计模式:桥接模式 blog目的:与图说话 版权声明:本文博客原创文章,博客,未经同意,不得转载.
- my97 日期控件
官网:http://www.my97.net/ 好多广告啊! 文档地址: http://www.mysuc.com/test/My97DatePicker/
- 我的MYSQL学习心得(九)
原文:我的MYSQL学习心得(九) 我的MYSQL学习心得(九) 我的MYSQL学习心得(一) 我的MYSQL学习心得(二) 我的MYSQL学习心得(三) 我的MYSQL学习心得(四) 我的MYSQL ...
- js面向对象+一般方法的选项卡
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...