什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)

IO密集型和CPU密集型

1. 两者的区别

1.1 什么是IO,什么是IO操作

什么是IO?

I/O输入/输出(Input/Output),分为IO设备和IO接口两个部分

什么是IO操作?

处理器访问任何寄存器和 Cache 等封装以外的数据资源都可以当成 I/O 操作,包括内存,磁盘,显卡等外部设备。

计算机的核心部件是计算单元,即CPU,相对于CPU来说,存储(访问内存)、接口(访问外设)都是I/O。

1.2 什么是IO密集型操作

IO密集型操作(I/O bound)

IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。

I/O bound的程序一般在达到性能极限时,CPU占用率仍然较低。这可能是因为任务本身需要大量I/O操作,而pipeline做得不是很好,没有充分利用处理器能力。

1.3 什么是CPU密集型

CPU密集型(CPU-bound)

CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/内存),I/O在很短的时间就可以完成,而CPU还有许多运算要处理,CPU Loading很高。

IO密集型 VS CPU密集型

计算密集型任务由于主要消耗CPU资源,因此,代码运行效率至关重要。Python这样的脚本语言运行效率很低,完全不适合计算密集型任务。对于计算密集型任务,最好用C语言编写。

2.使用C#代码说明两者的区别

2.1 代码说明

  1. 使用串行代码(不开启线程)拷贝文件并在拷贝完成之后将文件删除
  2. 使用并行(开启线程)拷贝文件并在拷贝完成之后将文件删除
  3. 使用两种文件数据:一种文件比较大,另一种文件比较零碎

2.2 代码粘贴

界面代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace IOIntensiveDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnSingleThreadOperation_Click(object sender, EventArgs e)
        {
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();

            Console.WriteLine("********************************单线程复制文件***********************************");

            string strSorcePath = tbSourcePath.Text;
            string strTargetPath = tbTargetPath.Text;

            for (int i = 0; i < 10; i++)
            {
                CopyFolder(strSorcePath, strTargetPath, i);
            }
        }

        private void CopyFolder(string strSorcePath, string strTargetPath, int i)
        {
            Console.WriteLine($"拷贝数据{i}开始:当前线程{Thread.CurrentThread.ManagedThreadId},开始时间:{DateTime.Now}");
            strTargetPath = System.IO.Path.Combine(strTargetPath,i.ToString());
            FileAPI.CopyDirectory(strSorcePath, strTargetPath);
            System.IO.Directory.Delete(strTargetPath,true);
            Console.WriteLine($"拷贝数据{i}完成:当前线程{Thread.CurrentThread.ManagedThreadId},开始时间:{DateTime.Now}");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();

            Console.WriteLine("********************************多线程复制文件***********************************");
            string strSorcePath = tbSourcePath.Text;
            string strTargetPath = tbTargetPath.Text;
            for (int i = 0; i < 10; i++)
            {
                int num = i;
                Task task = new Task(() => this.CopyFolder(strSorcePath, strTargetPath, num));
                task.Start();
            }
        }
    }
}

粘贴文件代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace IOIntensiveDemo
{
    /// <summary>
    /// 文件操作帮助类
    /// </summary>
    public class FileAPI
    {
        /// <summary>
        /// 拷贝文件夹
        /// </summary>
        /// <param name="srcPath"></param>
        /// <param name="destPath"></param>
        public static void CopyDirectory(string srcPath, string destPath)
        {
            try
            {
                if (!Directory.Exists(destPath))
                {
                    Directory.CreateDirectory(destPath);
                }
                List<string> listFolderPath =System.IO.Directory.GetDirectories(srcPath, "*", SearchOption.AllDirectories).ToList();
                listFolderPath=listFolderPath.OrderByDescending(a => a.Length).ToList();
                foreach (var item in listFolderPath)
                {
                    string strTargetPath = System.IO.Path.Combine(destPath, item.Substring(srcPath.Length + 1));
                    System.IO.Directory.CreateDirectory(strTargetPath);
                }
                List<string> listFilePath = System.IO.Directory.GetFiles(srcPath, "*", SearchOption.AllDirectories).ToList();
                int index = 0;
                foreach (var item in listFilePath)
                {
                    index++;
                    string strTargetPath = System.IO.Path.Combine(destPath, item.Substring(srcPath.Length+1));
                    System.IO.File.Copy(item, strTargetPath);
                }
            }
            catch (Exception ex)
            {
            }
        }
    }
}

2.3 两类数据说明

  1. 文件比较零碎
什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)
  • 2.文件比较大,并且比较单一
什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)

2.4 两类数据执行代码过程中的细节

2.4.1 文件比较大,并且比较单一

2.4.1.1 单线程运行细节
  1. 运行细节
什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)
  • 2.运行完毕耗时:总耗时:4分10秒-250s(总觉得在骂我自己)
什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)

2.4.1.2 多线程运行细节

  1. 运行细节
什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)
  • 2.运行完毕耗时:总耗时:1分30秒-90s
什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)

2.4.2 文件比较大,并且比较单一

2.4.2.1 单线程运行细节

什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)
  • 2.运行完毕耗时:总耗时:1分33秒-93s
什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)

2.4.2.2 多线程运行细节

  1. 运行细节
什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)
  • 2.运行完毕耗时:总耗时:1分30秒-90s
什么是IO密集型和CPU密集型以及在并行开发是需要注意的(1、2、3、4)

2.4 结论

前后呼应一下:

  1. 所谓的IO密集型操作时操作过程中IO操作密集,比如【2.4.2】 在大文件拷贝时IO操作过载,CPU操作明显处于富余的情况,在此类情况下多线程无法提升效率,甚至会比单线程还要慢,原因时文件在拷贝过程中频繁切换CPU时间片,需要不断的寻址,导致效率低下,此类情况下单线程效率要优于或持平多线程
  2. 所谓CPU密集型是指操作过程中CPU操作密集,比如【2.4.1】 尽管在拷贝文件过程中文件拷贝较多,但是拷贝速度太快,并没有文件拷贝持有IO操作,此时CPU操作明显处于过载情况,此类情况下多线程效率要优于单线程
  3. 对于IO密集型建议使用脚本语言进行编码,比如python,相对编码简单,编码效率快
  4. 对于CPU密集型建议使用编译型语言进行编码,比如C、C++、Java和C#

原文出处:CSDN【 愿你走出半生】

原文链接:https://blog.csdn.net/a13407142317/article/details/113665283

本文观点不代表Dotnet9立场,转载请联系原作者。

发表评论

登录后才能评论