我有一个程序,其中包含多个线程(超过100个)。由于线程数量众多,程序所需的内存非常昂贵,因此无法在PC上运行它。
我有一个运行程序的想法。让线程数为100。
1- i=1, flag = false
2- if(flag == true) reconstruct thread[i], thread[i+1], ..., thread[i+9] from snapshots file[i], file[i+1], ..., file[i+9]
3- run thread[i], thread[i+1], ..., thread[i+9] for one second
4- take a snapshots of thread[i], thread[i+1], ..., thread[i+9], and write the snapshots on file[i], file[i+1], ..., file[i+9]
5- kill thread[i], thread[i+1], ..., thread[i+9]
6- i = i + 10
7- if(i < 100) go to line 3
else i = 1, flag = true, go to line 2
如何用C ++或C#实现这个想法?
答案 0 :(得分:0)
我担心您正在考虑实施操作系统的大部分而不知道操作系统为您做了什么。
操作系统管理虚拟内存和正在运行的线程。如果您有很多线程,并且每个线程中都有很多数据,那么如果总内存使用量超过RAM,那么运行所有这些线程将是一个挑战。但是,操作系统将使用某种描述的页面文件作为计算机中虚拟内存系统的一部分。这导致虚拟内存大小受HDD大小限制,而不是受安装的RAM限制。
现在,您谈论备份/还原线程。去哪儿?想必您是指磁盘。但是,您的程序执行自己的磁盘备份/还原操作与通过虚拟内存系统及其页面文件为您执行操作的OS之间没有根本区别。在这两种情况下,您最终都将无法容纳在RAM中的数据存储在磁盘上:
如果仅在线程内分配和填充内存,则操作系统将通过页面文件在后台为您完成所有工作,最重要的是,您无需编写任何代码即可去做。
但是,如果您编写用于将数据保存/恢复到HDD的程序,则已经编写了很多源代码,并且除了让OS继续使用它之外,还没有其他更好的结果。
因此,如果两种方法最终都得到相似的结果,则如果性能相似,也就不足为奇了。就是这样;破坏虚拟内存页面文件的许多线程是s-l-o-o-o-w。区别在于,操作系统已经开发了许多年,以使其尽可能达到最佳状态(即,通过有效使用页面文件来协调线程调度),并且您很可能无法击败它。 >
这就是为什么线程池有用的原因。无需设置大量线程(每个线程都执行一个任务),而是将许多任务提交到线程池,然后让该池管理如何最好地运行这些任务。如果单个任务不依赖于其他任务执行某项操作(例如发布信号量等),则此功能特别强大。
如果使用得当,线程池将尽最大可能仔细检查所提交的任务列表,并赋予其发现自己正在运行的硬件的能力。这省去了编写代码来自己了解机器架构的麻烦(如果您有兴趣将线程数优化为内核数)。
这也可能导致虚拟内存系统对页面文件的分页要少得多,这意味着HDD的抖动将减少到最低限度。这是因为在同一时间运行的线程(线程,任务)少得多,因此只有那些任务的数据会被分页到RAM中。
这就是我要做的。使用线程池而不是大量单独的线程,依靠操作系统有效地管理所有虚拟内存,并避免编写大量复制操作系统功能的代码。
如果那还不够快,那么您要么必须拥有一台更大的计算机,要么开始编写代码以在整个计算机集群中以分布式方式运行。 ZeroMQ和OpenMPI只是实现这一目标的两种不同方式(OpenMPI是超级计算机专家传统上偏爱的一种方式。)