初学者很多对自己开发的软件使用硬件资源的时候并不注意,造成写出的东西不是很满意。

一般有两种情况:

1.写的都是同步单线程任务,不管你电脑有多少个核都不关我事 我就用你1个核所以不管怎么样都不会把CPU吃满。

这样的例子还是比较多的,在CPU出多核之后很多软件陆续已经将这些问题进行了修复,不过也还有这样的情况。

拿我常用的金山快盘同步盘这个软件来说吧,他在要进行一次同步任务前要先下载一份服务器端文件版本信息的比对数据,所以当我点立即同步的时候或者刚打开软件的时候他会马上使用网络进行下载(任务管理器或很多流量监控软件都可以监控到),下载完成后进行文件版本对比任务找出需要更新的文件,这个时候在 任务管理器 里的进程中可以看到金山快盘会很快占用300-500M左右的内存(这个视个人电脑硬件配置和这个金山快盘用户文件多少而变化)CPU利用率立马飙到50%(我用的这台电脑是双核的)而且只有一个核的利用率到达很高另一个核在睡觉。这种状态一直持续很长一段时间不怎么变化(可能我的文件数量比较多所以这个时间就会比较长)。

2.多线程任务不控制CPU利用率。

很多朋友写程序的时候可能比较少用到多任务多线程开发 或者 搞不好这个程序中的多任务多线程只会用一会儿而且很快就能完成这个作业,所以用到的时候也没注意这么多。

经常使用多任务多线程开发的朋友应该是比较清楚的,不需要看这个了;

咱们先看一下控速与不控诉的区别,对比下面两张图就可以很明白的看出来了。

CPU不受控的情况下开启4条线程跑立马就把CPU吃满了,而且居高不下,造成电脑卡的不行无法进行别的作业。

受控的情况:

看完图就很明白情况了吧!代码是最好交流的方式,那咱们来看一下代码:

基本任务接口:

 public interface ICpuManagementTask
{
void DoWork();
void DoWork(object a);
}

ICpuManagementTask

模拟作业,实现任务接口进行作业:

  public class ApplictionClass : ICpuManagementTask
{ public ApplictionClass(out ICpuManagementTask icmt)
{
icmt = this;
} public void DoWork()
{
// Thread Code
do
{
int a = ;
for (int i = ; i < ; i++)
{
a = i;
}
//System.Threading.Thread.Sleep(1);
//Console.WriteLine("Task is Running " + mesg + "Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId); } while (true);
} public void DoWork(object mesg)
{
// Thread Code
do
{
int a = ;
for (int i = ; i < ; i++)
{
a = i;
}
//System.Threading.Thread.Sleep(1);
//Console.WriteLine("Task is Running " + mesg + "Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId); } while (true);
}
}

模拟基本业务

模拟不受控实现方式:

  /// <summary>
/// 不受控的异步执行
/// </summary>
public void Test1(ICpuManagementTask icmt)
{
System.Threading.Tasks.Task T1 = new System.Threading.Tasks.Task(new Action(icmt.DoWork));
T1.Start(); System.Threading.Tasks.Task T2 = new System.Threading.Tasks.Task(new Action(icmt.DoWork));
T2.Start(); System.Threading.Tasks.Task T3 = new System.Threading.Tasks.Task(new Action(icmt.DoWork));
T3.Start(); System.Threading.Tasks.Task T4 = new System.Threading.Tasks.Task(new Action(icmt.DoWork));
T4.Start(); }

不受控TEST

前面这些都是很简单的,有点OO思想的一看就明白了不需要什么解释的。

既然要让任务占用硬件资源受控制那肯定是需要一些处理的,要跑的作业相当于托管在一个“容器”里面暂时叫他“自动管理CPU”吧,接下来先看一下这个“容器”

看到这个就很简单了吧!其实并没有什么神秘的,无非就是做两个事 一、创建任务 二、管理CPU使用率进行任务作业

咱们一个个看,首先看看这个枚举,他是自定义的几个模式对应当需要挂起线程时处理的事

public enum CpuManagementModelEnum
{
None, /// <summary>
/// 中断模式 允许自动关闭一下获得任务释放CPU资源
/// </summary>
BreakModel, /// <summary>
/// 睡眠模式 允许将活动任务设置为睡眠状态是否CPU资源
/// </summary>
SleepModel
}

管理模式枚举

 public virtual  void CreatParallelTask(Dictionary<Thread, object> list)
{
Action act = new Action(() =>
{
list.ToList().ForEach(a => a.Key.Priority = ThreadPriority.Lowest);
foreach (var item in list)
{
item.Key.Start(item.Value);
//break;
}
});
System.Threading.Tasks.ParallelOptions options = new System.Threading.Tasks.ParallelOptions();
options.MaxDegreeOfParallelism =list.Count ;
System.Threading.Tasks.Parallel.Invoke(options, new Action[] { act });
}

创建任务

创建任务也没什么比较难懂东西,就是把任务集合中的任务先用Action封装成方法 然后用System.Threading.Tasks.Parallel.Invoke 方法尽可能并行执行提供的每个操作。

后面这个控制并执行就有点复杂了,先看一下代码:

 public virtual void CpuManagement(Dictionary<Thread, object> task, float cpuUpper, CpuManagementModelEnum cm)
{
Console.WindowWidth = ;
Thread t = new Thread(() =>
{
float avgCpu = ;
PerformanceCounter[] counters = new PerformanceCounter[System.Environment.ProcessorCount];
for (int i = ; i < counters.Length; i++)
{
counters[i] = new PerformanceCounter("Processor", "% Processor Time", i.ToString());
} while (true)
{
avgCpu = ;
for (int i = ; i < counters.Length; i++)
{
float f = counters[i].NextValue();
avgCpu += f;
}
avgCpu = avgCpu / counters.Length; if (avgCpu >= cpuUpper)
{
Console.Write("Sleep CPU-AVG: "
+ Math.Round(avgCpu, ).ToString().PadLeft(, ' ') + "%"
+ " CoreCount:" + counters.Length
+ " BusyThreadCount:" + task.Count(a => a.Key.ThreadState == System.Threading.ThreadState.Running).ToString()
+ " ThreadTotalCount:" + task.Count);
foreach (var item in task)
{
if (item.Key.ThreadState != System.Threading.ThreadState.Suspended)
{
item.Key.Suspend();
switch (cm)
{
case CpuManagementModelEnum.None:
break;
case CpuManagementModelEnum.BreakModel:
break;
case CpuManagementModelEnum.SleepModel:
System.Threading.Thread.Sleep();
break;
default:
break;
}
}
}
Console.Write(" Wait... \r\n");
}
else
{
Console.Write("Run CPU-AVG: " + Math.Round(avgCpu, ).ToString().PadLeft(, ' ') + "%"
+ " CoreCount:" + counters.Length
+ " BusyThreadCount:" + task.Count(a => a.Key.ThreadState == System.Threading.ThreadState.Running).ToString()
+ " ThreadTotalCount:" + task.Count);
foreach (var item in task)
{
if (item.Key.ThreadState == System.Threading.ThreadState.Suspended)
{
item.Key.Resume();
switch (cm)
{
case CpuManagementModelEnum.None:
break;
case CpuManagementModelEnum.BreakModel:
break;
case CpuManagementModelEnum.SleepModel:
System.Threading.Thread.Sleep();
break;
default:
break;
}
}
}
Console.Write(" Buy... \r\n");
}
System.Threading.Thread.Sleep();
}
});
t.Priority = ThreadPriority.Highest;
t.Start();
}

CPU管理执行任务

这里面主要就是做两个事:一、是对整体CPU资源被占用超过一个基数的时候要对现有的任务管理集合中的任务进行挂起操作;

二、是对整体CPU资源被占用小于定的基数的时候 继续已挂起的线程;

这个方法的第二个参数就是咱们想设定的CPU资源被占用到多大的基数上限开始使这时候运行的程序挂起部分线程释放资源,比如你想让CPU保持在90%左右,留有一部分空间来处理别的进程突发占用的情况或者别的情况这要视场景而定了。

在这执行任务当中用到两个已经过时的API:

System.Threading.Thread中的Suspend和Resume ,看到msdn上的有个警告

大概是说如果使用挂起的话当这个线程正好持有锁的话这个AppDomain的其他线程很可能都被堵死了,或者是在挂起一个线程在执行一个类的构造函数这个AppDomin其他线程使用这个类会受阻。很容易发生死锁现象。

可能主要就是这个原因吧!有知道比较详细的朋友可以留言告诉我,大家互相学习嘛。。。

这两个方法上倒是写了一些:

关于解决死锁问题直接使用 System.Threading.Monitor 会更好,这里主要介绍CPU多核控速问题,所以上面代码就不修改了。这个关于多线程上的五种基本问题之一的 死锁 在这就不详细讨论了。

下面咱们再回头看一下 这种受控制的情况下如何在应用程序中实现:

  /// <summary>
/// 受控的并行执行
/// </summary>
/// <param name="icmt"></param>
public void Test2(ICpuManagementTask icmt)
{
AutomaticCpuManagement CPU = new AutomaticCpuManagement(); Dictionary<Thread, object> task = new Dictionary<Thread, object>();
task.Add(new Thread(new ParameterizedThreadStart(icmt.DoWork)), System.DateTime.Now);
task.Add(new Thread(new ParameterizedThreadStart(icmt.DoWork)), System.DateTime.Now.AddSeconds());
task.Add(new Thread(new ParameterizedThreadStart(icmt.DoWork)), System.DateTime.Now.AddSeconds());
task.Add(new Thread(new ParameterizedThreadStart(icmt.DoWork)), System.DateTime.Now.AddSeconds()); CPU.CreatParallelTask(task);
CPU.CpuManagement(task, 90F, AutomaticCpuManagement.CpuManagementModelEnum.BreakModel);
}

受控制实现

启动调试 的两条代码:

 static void Main(string[] args)
{
ICpuManagementTask icmt;
ApplictionClass app = new ApplictionClass(out icmt); // app.Test1(icmt);
//Console.ReadKey(); app.Test2(icmt);
Console.ReadKey();
}

启动调试

分别调试两种方式进行观察就得到开头所看到的占用硬件资源不同的情况了。

CPU多核控速的更多相关文章

  1. paip.提升性能---mysql 优化cpu多核以及lan性能的关系.

    paip.提升性能---mysql 优化cpu多核以及lan性能的关系. 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http:/ ...

  2. R语言的并行运算(CPU多核)

    通常R语言运行都是在CPU单个核上的单线程程序.有时我们会有需求对一个向量里的元素应用相同的函数,最终再将结果合并,并行计算可以大幅节约时间. 为了支持R的并行运算, parallel包已经被纳入了R ...

  3. CPU 多核指令 —— WFE 原理【原创】

    转自:http://tinylab.org/arm-wfe/ Zhang Binghua 创作于 2020/05/19 打赏 微信公众号   知识星球 关注 @泰晓科技 与数千位一线 Linux 工程 ...

  4. Msbuild利用cpu多核加速

    msbuild /t:Rebuild /p:Configuration=Release /m /m 自动检测cpu数量启动对应数量进程

  5. 充分利用CPU多核的处理能力 innodb_read_io_threads和innodb_write_io_threads

    https://book.2cto.com/201402/40300.html 在MySQL5.1.X版本中,innodb_file_io_threads参数默认是4,该参数在Linux系统上是不可更 ...

  6. Linux 多核下绑定硬件中断到不同 CPU(IRQ Affinity) 转

    硬件中断发生频繁,是件很消耗 CPU 资源的事情,在多核 CPU 条件下如果有办法把大量硬件中断分配给不同的 CPU (core) 处理显然能很好的平衡性能.现在的服务器上动不动就是多 CPU 多核. ...

  7. 多CPU,多核,多进程,多线程

    当面临这些问题的时候,有两个关键词无法绕开,那就是并行和并发. 首先,要先了解几个概念: 1.进程是程序的一次执行. 2.进程是资源分配的基本单位(调度单位). 3.一个进程可以包括多个线程. 4.在 ...

  8. 软件设计师考试计算机系统知识——CPU

    第一章: 计算机系统知识 1.1.1计算机系统硬件的基本组成 运算器.控制器.存储器.输入设备.输出设备 1.1.2 中央处理器 ①CPU的功能: a.程序控制:CPU通过执行指令来控制程序执行的顺序 ...

  9. cpu 性能

    我们平时使用的CPU利用率方法是极具误导性的,并且一年更甚一年.那么什么是CPU利用率?是你的CPU到底有多忙,是像“% CPU”这样到处在用的指标所显示的那样吗? 在top命令里,你看到90%的CP ...

随机推荐

  1. ASCII码(转)

    ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧 ...

  2. drawText文字绘制知识

    drawText(String text, float x, float y, Paint paint) x,y是基于文字基本线的,而不是android坐标系的左上角. 使用staticLayout进 ...

  3. webcollector 2.x 爬取搜狗搜索结果页

    /** * 使用搜狗搜索检索关键字并爬取结果集的标题 * @author tele * */ public class SougouCrawler extends RamCrawler{ public ...

  4. solrj 7.x Expected mime type application/octet-stream but got text/html.

    出现这种情况是因为baseurl填写错误,最开始的时候我写的是用tomcat启动后浏览器中访问solr的地址 结果就出现了如题的异常,当然提示的是404,还有可能提示405,Method not al ...

  5. win10 支持默认把触摸提升鼠标事件 打开 Pointer 消息

    原文:win10 支持默认把触摸提升鼠标事件 打开 Pointer 消息 在 WPF 经常需要重写一套触摸事件,没有UWP的Pointer那么好用. 如果一直都觉得 WPF 的触摸做的不好,或想解决 ...

  6. 使用 Microsoft.UI.Xaml 解决 UWP 控件和对老版本 Windows 10 的兼容性问题

    原文 使用 Microsoft.UI.Xaml 解决 UWP 控件和对老版本 Windows 10 的兼容性问题 虽然微软宣称 Windows 10 将是最后一个 Windows 版本,但由于年代跨越 ...

  7. PFIF网上寻人协议

    原文:http://www.csdn.net/article/2013-04-22/2814980 本文的主要内容来自Wikipedia(http://en.wikipedia.org/wiki/Pe ...

  8. Boost智能指针-基础知识

    简单介绍 内存管理一直是 C++ 一个比較繁琐的问题,而智能指针却能够非常好的解决问题,在初始化时就已经预定了删除.排解了后顾之忧.1998年修订的第一版C++标准仅仅提供了一种智能指针:std::a ...

  9. Android 调用系统分享文字、图片、文件,可直达微信、朋友圈、QQ、QQ空间、微博

    原文:Android 调用系统分享文字.图片.文件,可直达微信.朋友圈.QQ.QQ空间.微博 兼容SDK 18以上的系统,直接调用系统分享功能,分享文本.图片.文件到第三方APP,如:微信.QQ.微博 ...

  10. 使用 LaTex 制作个人简历(CV,英文版)

    \documentclass[12pt]{article} \textwidth=6.5in \textheight=9in \topmargin=-1.1in \headheight=0in \he ...