关于C#线程,线程池和并行运算的简单使用和对比

前言:看了书上两个使用C#4.0并行编程的demo,又对照以前收藏的网上几篇讲述线程池的雄文,一并整理,写个示例总结一下。写这篇文章的时候,发现关于线程的好几个基础的重要的知识点自己都不熟悉,而且可能习惯性认知浅薄,所以痛苦的无以复加,不知道到底要说什么。不想看文章的可以直接下载最后的示例,本文代码主要参考Marc Clifton的“.NET's ThreadPool Class - Behind The Scenes”,对新手也许有帮助。

  参考:

  http://msdn.microsoft.com/zh-cn/library/system.threading.threadpool(VS.80).aspx

  http://www.codeproject.com/KB/threads/threadtests.aspx

  http://www.codeproject.com/KB/threads/smartthreadpool.aspx

  http://blog.zhaojie.me/2009/07/thread-pool-1-the-goal-and-the-clr-thread-pool.html  (老赵的浅谈线程池上中下三篇)

  先大概看一下控制台应用程序的Main方法的主要代码:

static bool done = false;

static decimal count2 = 0;

static int threadDone = 0;//标志启用线程数?

static System.Timers.Timer timer = new System.Timers.Timer(1000);

static decimal[] threadPoolCounters = new decimal[10];

static Thread[] threads = new Thread[10];

static System.Timers.Timer[] threadTimers = new System.Timers.Timer[10];

static void Main(string[] args)

{

timer.Stop();

/*当 AutoReset 设置为 false 时,Timer 只在第一个 Interval 过后引发一次 Elapsed 事件。

若要保持以 Interval 时间间隔引发 Elapsed 事件,请将 AutoReset 设置为 true。*/

timer.AutoReset = false;

timer.Elapsed += new ElapsedEventHandler(OnTimerEvent);//当timer.Start()时,触发事件

decimal total = 0;

// raw test

decimal count1 = SingleThreadTest();//单一线程,一跑到底

Console.WriteLine("Single thread count = " + count1.ToString());

// create one thread, increment counter, destroy thread, repeat

Console.WriteLine();

CreateAndDestroyTest();//创建一个线程,运算,
然后销毁该线程 重复
前面的动作

Console.WriteLine("Create and destroy per count = " + count2.ToString());

// Create 10 threads and run them simultaneously

//一次性创建10个线程,然后遍历使线程执行运算

Console.WriteLine();

InitThreadPoolCounters();

InitThreads();

StartThreads();

while (threadDone != 10) { };

Console.WriteLine("10 simultaneous threads:");

for (int i = 0; i < 10; i++)

{

Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

total += threadPoolCounters[i];

}

Console.WriteLine("Total = " + total.ToString());

Console.WriteLine();

Console.WriteLine("///////////////////////////////////////////////////");

// using ThreadPool

//直接通过线程池的QueueUserWorkItem方法,按队列执行10个任务

Console.WriteLine();

Console.WriteLine("ThreadPool:");

InitThreadPoolCounters();

QueueThreadPoolThreads();

while (threadDone != 10) { };

Console.WriteLine("ThreadPool: 10 simultaneous threads:");

total = 0;

for (int i = 0; i < 10; i++)

{

// threadTimers[i].Stop();

// threadTimers[i].Dispose();

Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

total += threadPoolCounters[i];

}

Console.WriteLine("Total = " + total.ToString());

// using SmartThreadPool

//通过Amir Bar的SmartThreadPool线程池,利用QueueUserWorkItem方法,按队列执行10个任务

Console.WriteLine();

Console.WriteLine("SmartThreadPool:");

InitThreadPoolCounters();

QueueSmartThreadPoolThreads();

while (threadDone != 10) { };

Console.WriteLine("SmartThreadPool: 10 simultaneous threads:");

total = 0;

for (int i = 0; i < 10; i++)

{

Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

total += threadPoolCounters[i];

}

Console.WriteLine("Total = " + total.ToString());

// using ManagedThreadPool

//通过Stephen Toub改进后的线程池,利用QueueUserWorkItem方法,按队列执行10个任务

Console.WriteLine();

Console.WriteLine("ManagedThreadPool:");

InitThreadPoolCounters();

QueueManagedThreadPoolThreads();

while (threadDone != 10) { };

Console.WriteLine("ManagedThreadPool: 10 simultaneous threads:");

total = 0;

for (int i = 0; i < 10; i++)

{

Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

total += threadPoolCounters[i];

}

Console.WriteLine("Total = " + total.ToString());

// using C#4.0 Parallel

//通过Tasks.Parallel.For进行并行运算

Console.WriteLine();

Console.WriteLine("Parallel:");

InitThreadPoolCounters();

UseParallelTasks();

while (threadDone != 10) { };

Console.WriteLine("Parallel: 10 simultaneous threads:");

total = 0;

for (int i = 0; i < 10; i++)

{

Console.WriteLine("T" + i.ToString() + " = " + threadPoolCounters[i].ToString() + " ");

total += threadPoolCounters[i];

}

Console.WriteLine("Total = " + total.ToString());

}

  我们可以先熟悉一下大致思路。代码中,我们主要依靠输出的数字count或者total来判断哪个方法执行效率更高(原文是How Hign Can I Count?),通常输出的数字越大,我们就认为它”干的活越多“,效率越高。主要实现过程就是通过一个静态的System.Timers.Timer对象的timer实例,设置它的Interval属性和ElapsedEventHandler事件:

static System.Timers.Timer timer = new System.Timers.Timer(1000);

/*当 AutoReset 设置为 false 时,Timer 只在第一个 Interval 过后引发一次 Elapsed 事件。

若要保持以 Interval 时间间隔引发 Elapsed 事件,请将 AutoReset 设置为 true。*/

timer.AutoReset = false;

timer.Elapsed += new ElapsedEventHandler(OnTimerEvent);//当timer.Start()时,触发事件

  其中,timer的事件触发的函数:

static void OnTimerEvent(object src, ElapsedEventArgs e)

{

  done = true;

}

  每次timer.Start执行的时候,一次测试就将开始,这样可以确保测试的不同方法都在1000毫秒内跑完。

  下面开始具体介绍几个方法:

  A、线程

  这个非常简单,就是通过主线程计算在1000毫秒内,count从0递增加到了多少:

/// <summary>

/// 单一线程,一跑到底

/// </summary>

/// <returns></returns>

static decimal SingleThreadTest()

{

done = false;

decimal counter = 0;

timer.Start();

while (!done)

{

++counter;

}

return counter;

}

  while判断可以保证方法在1000毫秒内执行完成。

  B、多线程

  这个多线程方法比较折腾,先创建线程,然后运行,最后销毁线程,这就是一个线程执行单元,重复10次这个线程执行单元。

/// <summary>

/// 创建一个线程,运算,然后销毁该线程 重复前面的动作

/// </summary>

static void CreateAndDestroyTest()

{

done = false;

timer.Start();

while (!done)

{

Thread counterThread = new Thread(new ThreadStart(Count1Thread));

counterThread.IsBackground = true;//后台线程

counterThread.Start();

while (counterThread.IsAlive) { };

}

}

  那个ThreadStart委托对应的方法Count1Thread如下:

static void Count1Thread()

{

++count2; //静态字段count2自增

}

  从表面上看,大家估计都可以猜到,效果可能不佳。

  C、还是多线程

  这个方法不判断线程的执行状态,不用等到一个线程销毁后再创建一个线程,然后执行线程方法。线程执行的方法就是根据线程的Name找到一个指定数组的某一索引,并累加改变数组的值:

static void InitThreadPoolCounters()

{

threadDone = 0;

for (int i = 0; i < 10; i++)

{

threadPoolCounters[i] = 0;

}

}

/// <summary>

/// 初始化10个线程

/// </summary>

时间: 2024-11-05 18:51:55

关于C#线程,线程池和并行运算的简单使用和对比的相关文章

一起谈.NET技术,关于C#线程,线程池和并行运算的简单使用和对比

前言:看了书上两个使用C#4.0并行编程的demo,又对照以前收藏的网上几篇讲述线程池的雄文,一并整理,写个示例总结一下.写这篇文章的时候,发现关于线程的好几个基础的重要的知识点自己都不熟悉,而且可能习惯性认知浅薄,所以痛苦的无以复加,不知道到底要说什么.不想看文章的可以直接下载最后的示例,本文代码主要参考Marc Clifton的".NET's ThreadPool Class - Behind The Scenes",对新手也许有帮助. 参考: http://msdn.micros

JAVA之旅(十五)——多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止

JAVA之旅(十五)--多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止 我们接着多线程讲 一.生产者和消费者 什么是生产者和消费者?我们解释过来应该是生产一个,消费一个,的意思,具体我们通过例子来说 package com.lgl.hellojava; //公共的 类 类名 public class HelloJJAVA { public static void main(String[] args) { /** * 生产者和消费者

线程池的介绍及简单实现

服务器程序利用线程技术响应客户请求已经司空见惯,可能您认为这样做效率已经很高,但您有没有想过优化一下使用线程的方法.该文章将向您介绍服务器程序如何利用线程池来优化性能并提供一个简单的线程池实现. 线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利

c#中子线程控制进度条的一个简单例子

这个问题来自社区提问,代码保留一份用来以后回答 using System; using System.ComponentModel; using System.Windows.Forms; namespace WindowsApplication4 ...{ /**//// <summary> /// gui 类 /// </summary> public partial class Form1 : Form ...{ public Form1() ...{ InitializeC

java-多线程 | 线程安全和线程同步

线程安全 线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用.不会出现数据不一致或者数据污染. 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据. 概述 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 或者说:一个类或者程序所提供的接口对于

Linux多线程 创造新线程 线程的生命周期

创造新线程 一.线程的ID pthread_t:结构体(FreeBSD5.2.Mac OS10.3)/unsigned long int(linux)                /usr/include/bits/pthreadtypes.h 获取线程ID:pthread_self() 一个实例:获取主线程ID #include "apue.h" int main(){    pid_t pid;    pthread_t tid;     pid = getpid();    t

将ios代码在后台(子线程)执行的两种简单方式

a.使用gcd    //切换到线程中执行             dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{                 // Do the work in background                 [[MyManager shareInstance] myMethod];             }); b.使用performSelectorI

Core Java-多线程-线程的生命周期

0. 在介绍线程前我们先看一下什么是进程? 进程是线程的母亲,如果在大学计算机课程里读过操作系统一定不会陌生. 所谓进程,它是计算机程序关于某数据集上的一次活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础. 罗里吧嗦一大堆,还是不够简洁? 那就一句话来表达吧:进程是正在执行的程序实例.   进程的内存布局 逻辑上一个进程可以划分为以下几部分(段): * 文本: 程序的指令 * 数据: 程序使用的静态变量 * 堆:   程序可以从该区域动态分配额外内存 * 栈:   随函数调用, 返

Java游戏起步:(一)线程与线程池

任何游戏都至少需要运行两个线程,主线程和GUI线程而线程池是一个管理运行线程的有用工具,下面的代码示范了一个线程池的实现方法~~************************************************(ThreadPool.java)import java.util.LinkedList; /** 线程池是一组线程,限制执行任务的线程数*/public class ThreadPool extends ThreadGroup { private boolean isAli