本学期的计算机系统课接近尾声,这是我要写的最后一篇博客,大概也是我最想要写的一篇,结合备考软考和计算机系统课上老师讲的一些知识谈一谈关于系统io,并且结合我在项目中的实践谈一谈学习了计算机系统对我的帮助。
io操作的几种方式
1.直接程序控制
直接程序控制是指外设数据的输入输出过程是在CPU执行程序的控制下完成的。这种方式分为无条件传送和程序查询方式两种情况。
分为无条件传送和程序查询方式。
(1)无条件传送:
在此情况下。外设总是准备好的,他可以无条件的随时接收CPU发来的输出数据,也能够无条件地随时向cpu提供需要输入的数据。
(2)程序查询方式
在这种方式下,利用查询方式进行输入输出,就是通过cpu执行程序来查询外设状态,判断外设是否准备好接受数据或接收好了向cpu输入的数据。根据这种状态,cpu有针对性的为外设的输入输出服务。
2.中断方式
利用中断的方式完成数据的输入输出过程为:当I/O系统与外设交换数据时,CPU无需等待也不必去查询I/O的状态,而可以抽身来处理其他的任务。当系统I/O准备好以后,则发出中断请求信号通知CPU,CPU接到中断请求信号后,保存正在执行的程序现场,转入I/O中断服务程序的执行,完成与I/O系统的交换数据,然后再返回被打断的程序继续执行。与程序控制方式相比,中断方式因为CPU无需等待而提高了效率。
3.DMA方式
DMA方式是指数据在内存与I/O设备间的直接成块传送,即在内存与I/O设备间传送一个数据块的过程中,不需要CPU的任何干涉,只需要CPU在过程开始启动与过程结束时的处理,实际操作由DMA硬件直接执行完成,CPU在此传送过程中可做别的事情。
我遇到的关于I/O的问题
这学期,在做项目时,我深刻的了解到了理解计算机系统的重要性。在做一个关于人工智能的项目时,我需要从一个视频中一帧一帧的读取图片,然后将图片显示在Frame界面上,(这中间会用级联分类器做一些检测的工作)当时错误的代码大概是下面这个样子(记得不是很清楚了),也就是说因为opencv在视频中读取的图片是Mat类型的而在Frame上不能直接显示这种类型的图片,因此我当时的想法就是直接把这个图片存储在磁盘上,然后直接把路径传给UserInter,UserInter在磁盘上去读这张图然后显示出来,也就是因为这个想法,我在这个部分卡了一个上午,程序没有按照我的想法进行输出,UserInter上一帧的图片也没有显示,这还不是最崩溃的,最崩溃的是居然一条的报错信息也没有,没有报错信息的错误是最令人难以修改的,我大胆的猜测这个问题出在哪里,机缘巧合之下我设置了一个变量,利用这个变量,我让读取视频帧图片与UserInter显示图片之间存在了一个时间差,没想到图片居然显示出来了,我又仔细思索,想到了计算机系统课上的DMA的I/O方式,终于想出了问题的所在,程序执行的速度很快,在磁盘上存数据又很慢,在DMA方式下CPU不会等待磁盘存储图片操作的完成就会去执行接下来的语句,这样,当程序去显示某一帧的图片时,实际上磁盘中还没有存上这一张图片,UserInter当然也就无法显示了。之后我换了另一种方法,直接把Mat类型的图片转化为了BufferedImage,在内存中进程图片的传输,问题解决了,功能也实现了,至此一个上午过去了,这个问题也终于解决了。经过这件事,我深深地感受到了了解计算机系统的重要性,谁知道以后还会遇到什么千奇百怪难以解决的问题,了解计算机的底层才能应对一切。
出错的代码
public void run() {
if(!video.isOpened()) {
System.out.println("Open File Error");//无法打开文件异常事件处理
}else {
Mat videoFrame=new Mat();
Mat result=new Mat();
while(true){
if(userInter.videoPlay) {
video.read(videoFrame);
}
for(int k=0;k<detections.size();k++) {
videoFrame=detections.get(k).ObjectDetection(videoFrame);
}
for(int i=0;i<detections.size();i++) {
userInter.setText("场景中有"+detections.get(i).objectNumber+"个"+detections.get(i).name+"\n");
// System.out.println("场景中有"+detections.get(i).objectNumber+"个"+detections.get(i).name+"\n");
for(int j=0;j<detections.get(i).objectNumber;j++) {
userInter.setText("第"+(j+1)+"个"+"的坐标为("+detections.get(i).x[j]+","+detections.get(i).y[j]+")\n");
}
detections.get(i).objectNumber=0;
}
Imgcodecs.imwrite(imagePath);
userInter.setVideoImage(imagePath);//设置用户界面显示的图片
userInter.repaint();
// try{
// Thread.sleep(10);
// }catch(InterruptedException e) {
// e.printStackTrace();
// }
}
}
}
改正后的代码
public void run() {
if(!video.isOpened()) {
System.out.println("Open File Error");//无法打开文件异常事件处理
}else {
Mat videoFrame=new Mat();
Mat result=new Mat();
while(true){
if(userInter.videoPlay) {
video.read(videoFrame);
}
for(int k=0;k<detections.size();k++) {
videoFrame=detections.get(k).ObjectDetection(videoFrame);
}
for(int i=0;i<detections.size();i++) {
userInter.setText("场景中有"+detections.get(i).objectNumber+"个"+detections.get(i).name+"\n");
// System.out.println("场景中有"+detections.get(i).objectNumber+"个"+detections.get(i).name+"\n");
for(int j=0;j<detections.get(i).objectNumber;j++) {
userInter.setText("第"+(j+1)+"个"+"的坐标为("+detections.get(i).x[j]+","+detections.get(i).y[j]+")\n");
}
detections.get(i).objectNumber=0;
}
Image image=matToBufferedImage(videoFrame);
userInter.setVideoImage(image);//设置用户界面显示的图片
userInter.repaint();
// try{
// Thread.sleep(10);
// }catch(InterruptedException e) {
// e.printStackTrace();
// }
}
}
}
事实上我在使用java代码调用python代码是也遇到了一个让我记忆深刻的错误,python子进程的阻塞导致父进程也无法正常进行,最后也是依靠计算机系统的知识解决的,虽然这学期的计算机系统课已经结束了,但是我想我对计算机系统的学习才刚刚开始。