线程系列02,多个线程同时处理一个耗时较长的任务以节省时间
2014-09-18 22:48
309 查看
当面对一个耗时较长的任务时,我们可以把这个任务切分成多个部分,然后同时交给多个线程处理。
□ 统计字节数组一个比较耗时的方式
以下来统计一个字节数组的大小。
如果把统计工作同时交给多个线程,是否可以把统计时间省下来呢?
□ 同时使用多个线程
现在要对"统计字节数组大小"这个任务进行均分、切分。首先面临的问题是:按什么标准均分?
--这个完全是靠个人喜好,可以让2个线程,3个线程......来处理。在这里,就根据CPU的数量来均分,因为CPU的数量可以通过Environment.ProcessorCount获得。
面临的第二问题是:均分什么?
--比如有4个CPU
--那可以把任务分成4个线程同时处理
--把字节数组的长度均分,比如字节数组的长度是1000,均分成4段,每段长度为250
--把字节数组的大小分成4个放一个数组里,即[sum1, sum2, sum3, sum4],所有的元素加起来就是字节数组的总大小
以上,统计字节数组大小的方式倒不是最重要的,线程部分才是重点:
○ 有几个CPU,就有几个线程
○ 线程的实例方法Start可以传递object类型的参数
○ 线程的实例方法Join,用来保证执行完上一个线程再执行下一个线程
在这里,使用多线程同时处理一个任务,效率差不多提高了2.6倍!
总结:
○ 对于一个比较耗时的任务可以同时交给多个线程处理
○ 线程的实例方法Join保证执行完上一个线程再执行下一个线程
线程系列包括:
□ 统计字节数组一个比较耗时的方式
以下来统计一个字节数组的大小。
class Program
{
static byte[] values = new byte[500000000];
static void Main(string[] args)
{
GenerateByteArray();
Console.WriteLine("正在统计字节数");
Stopwatch watch = new Stopwatch();
watch.Start();
long total = 0;
for (int i = 0; i < values.Length; i++)
{
total += values[i];
}
watch.Stop();
Console.WriteLine("统计结果为:" + total);
Console.WriteLine("计算时间为:" + watch.Elapsed);
}
static void GenerateByteArray()
{
var r = new Random(987);
for (int i = 0; i < values.Length; i++)
{
values[i] = (byte)r.Next(10);
}
}
}
如果把统计工作同时交给多个线程,是否可以把统计时间省下来呢?
□ 同时使用多个线程
现在要对"统计字节数组大小"这个任务进行均分、切分。首先面临的问题是:按什么标准均分?
--这个完全是靠个人喜好,可以让2个线程,3个线程......来处理。在这里,就根据CPU的数量来均分,因为CPU的数量可以通过Environment.ProcessorCount获得。
面临的第二问题是:均分什么?
--比如有4个CPU
--那可以把任务分成4个线程同时处理
--把字节数组的长度均分,比如字节数组的长度是1000,均分成4段,每段长度为250
--把字节数组的大小分成4个放一个数组里,即[sum1, sum2, sum3, sum4],所有的元素加起来就是字节数组的总大小
class Program
{
static byte[] values = new byte[500000000];
//分段统计的大小放该数组,比如分成4等份,[10000,10005,10008,10009]
private static long[] partialSum;
//把values数组长度均等分,比如长度1000,分成4粉,那partialSize就是250
private static int partialSize;
static void Main(string[] args)
{
//根据CPU的数量确定数组的长度
partialSum = new long[Environment.ProcessorCount];
//根据CPU的数量确定数组长度均等分
partialSize = values.Length/Environment.ProcessorCount;
GenerateByteArray();
Console.WriteLine("正在统计字节数");
Stopwatch watch = new Stopwatch();
watch.Start();
long total = 0;
for (int i = 0; i < values.Length; i++)
{
total += values[i];
}
watch.Stop();
Console.WriteLine("统计结果为:" + total);
Console.WriteLine("计算时间为:" + watch.Elapsed);
Console.WriteLine();
watch.Reset();
watch.Start();
Thread[] threads = new Thread[Environment.ProcessorCount];
for (int i = 0; i < Environment.ProcessorCount; i++)
{
threads[i] = new Thread(SumPartial);
threads[i].Start(i);
}
//保证一个线程结束再执行下一个线程
for (int i = 0; i < Environment.ProcessorCount; i++)
{
threads[i].Join();
}
//统计总大小
long total2 = 0;
for (int i = 0; i < Environment.ProcessorCount; i++)
{
total2 += partialSum[i];
}
watch.Stop();
Console.WriteLine("使用分段线程统计的大小:" + total2);
Console.WriteLine("计算时间为:" + watch.Elapsed);
}
/// <summary>
/// 分段统计字节数组的大小
/// </summary>
/// <param name="partialNumber">比如有4个CPU,partialNumber可能的值是0, 1, 2, 3</param>
static void SumPartial(object partialNumber)
{
long sum = 0;
int partialNumberAsInt = (int)partialNumber;
int baseIndex = partialNumberAsInt * partialSize;
for (int i = baseIndex; i < baseIndex + partialSize; i++)
{
sum += values[i];
}
partialSum[partialNumberAsInt] = sum;
}
/// <summary>
/// 创建字节数组
/// </summary>
static void GenerateByteArray()
{
var r = new Random(987);
for (int i = 0; i < values.Length; i++)
{
values[i] = (byte)r.Next(10);
}
}
}
以上,统计字节数组大小的方式倒不是最重要的,线程部分才是重点:
○ 有几个CPU,就有几个线程
○ 线程的实例方法Start可以传递object类型的参数
○ 线程的实例方法Join,用来保证执行完上一个线程再执行下一个线程
在这里,使用多线程同时处理一个任务,效率差不多提高了2.6倍!
总结:
○ 对于一个比较耗时的任务可以同时交给多个线程处理
○ 线程的实例方法Join保证执行完上一个线程再执行下一个线程
线程系列包括:
线程系列01,前台线程,后台线程,线程同步
线程系列02,多个线程同时处理一个耗时较长的任务以节省时间
线程系列03,多线程共享数据,多线程不共享数据
线程系列04,传递数据给线程,线程命名,线程异常处理,线程池
线程系列05,手动结束线程
线程系列06,通过CLR代码查看线程池及其线程
线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步
线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁
线程系列09,线程的等待、通知,以及手动控制线程数量线程系列10,无需显式调用线程的情形
相关文章推荐
- Activity、BroadcastReceiver、Service,只要是有长时间处理的任务,就需要重新开一个线程?!
- 异常信息:CLR无法从COM 上下文0x645e18 转换为COM上下文0x645f88,这种状态已持续60秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作.这种情况通常会影响到
- android 直接在activity/broadcast receiver中启动子线程来处理长时间的耗时任务不行吗?
- AsyncTask的套路(线程间通信中处理耗时任务的工具封装类)
- 异常信息:CLR无法从COM 上下文0x645e18 转换为COM上下文0x645f88,这种状态已持续60秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作.这种情况通常会影响到性能,甚至可能导致应用程序不响应或者使用的内存随时间不断累积
- 给定一个单向链表(长度未知),请设计一个既节省时间又节省空间的算法来找出该链表中的倒数第m个元素。实现这个算法,并为可能出现的特例情况安排好处理措施。“倒数第m个元素”是这样规定的:当m=0时,链表的
- 开一个线程来处理 耗时的操作
- 两个线程A和B,任务都是打印当前时间,要求编码实现:线程A和B同时启动后,以先A后B的方式任务交叉执行10次。
- CLR 无法从 COM 上下文 0x1a2740 转换为 COM 上下文 0x1a28b0,这种状态已持续 60 秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作
- 两个线程A和B,任务都是打印当前时间,要求编码实现:线程A和B同时启动后,以先A后B的方式任务交叉执行10次。
- Azkaban的线程系列 37:QueueProcessor线程的任务处理&executor存活监控
- 如何在asp.net中使用多线程及队列,异步处理一个耗时的任务(原创)
- 两个线程同时调用同一个处理函数的互斥问题
- 为什么不能直接在BroadCastReceiver中开一个线程执行耗时任务
- 两个线程同时调用同一个处理函数的互斥问题
- 使用回调和线程处理一个耗时响应过程
- 两个线程同时调用同一个处理函数的互斥问题
- 使用线程同时处理一个DataTable
- 异常信息:CLR无法从COM 上下文0x645e18 转换为COM上下文0x645f88,这种状态已持续60秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作.这种情况通常会影响到
- 一个主线程下有多个子线程任务,主线程必须在100秒内将子线程执行的集合结果进行处理返回