操作系统实习报告

目录

1.题目内容. 1

1.1设计一:进程调度. 1

1.2设计五:磁盘调度管理. 1

2.题目要求. 1

2.1设计一:进程调度. 1

2.2设计五:磁盘调度管理. 1

3.设计思想. 2

3.1设计一:进程调度. 2

3.2设计五:磁盘调度管理. 3

4.算法分析. 4

4.1设计一:进程调度. 4

4.1.1最高优先级优先算法. 4

4.1.2时间片轮转调度算法. 4

4.2设计五:磁盘调度管理. 5

4.2.1扫描算法SCAN5

4.2.2循环扫描算法CSCAN5

5.核心代码. 5

5.1设计一:进程调度. 5

5.1.1进程控制块结构. 5

5.1.2 create1()、create2()创建进程函数. 5

5.1.3 insert1()、insert2()插入函数. 7

5.1.4最高优先级优先和时间片轮转调度算法. 8

5.2设计五:磁盘调度管理. 10

5.2.1 GetNum()随机生成磁道号序列函数. 10

5.2.2 PaiXu()寻道长度排序函数. 10

5.2.3扫描算法(SCAN)和循环扫描算法(CSCAN)11

6.测试数据或截图. 15

6.1设计一:进程调度. 15

6.1.1最高优先级优先算法. 15

6.1.2时间片轮转调度算法. 17

6.2设计五:磁盘调度管理. 18

6.2.1扫描算法SCAN18

6.2.2循环扫描算法CSCAN19

6.2.3各类算法性能比较. 20

7.心得体会. 20

 


1.题目内容

1.1设计一:进程调度

进程管理是操作系统中的重要功能,用来创建进程、撤消进程、实现进程状态转换,它提供了在可运行的进程之间复用CPU的方法。在进程管理中,进程调度是核心,因为在采用多道程序设计的系统中,往往有若干个进程同时处于就绪状态,当就绪进程个数大于处理器数目时,就必须依照某种策略决定哪些进程优先占用处理器。本设计模拟在单处理器情况下的进程调度,目的是加深对进程调度工作的理解,掌握最高优先级优先算法和时间片轮转调度算法的优缺点。

1.2设计五:磁盘调度管理

加深对请求磁盘调度管理实现原理的理解,掌握磁盘调度算法。通过编程实现扫描算法SCAN、循环扫描算法CSCAN两种磁盘调度算法。

2.题目要求

2.1设计一:进程调度

设计程序模拟单处理机系统中的进程调度算法,实现最高优先级优先算法、时间片轮转调度算法两种算法。

每个进程由一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等。

进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数产生)。进程的到达时间为进程输入的时间。

进程的运行时间以时间片为单位进行计算。

每个进程的状态可以是就绪W(Wait)、运行R(Run)或完成F(Finish)3中状态之一。

2.2设计五:磁盘调度管理

设定开始磁道号寻道范围,依据起始扫描磁道号和最大磁道号数,随机产生要进行寻道的磁道号序列。选择扫描算法SCAN、循环扫描算法CSCAN两种磁盘调度算法,显示该算法的磁道访问顺序,计算出移动的磁道总数和平均寻道总数。并对算法性能进行分析对比。

3.设计思想

3.1设计一:进程调度

进程是程序在处理机上的执行过程。进程存在的标识是进程控制块(PCB),所谓系统创建一个进程,就是由系统为某个程序设置一个PCB,用于对该进程进行控制和管理。进程任务完成,由系统收回其PCB,该进程便消亡。每个进程可有三个状态:运行状态、就绪状态和完成状态。因此设计三个链队列,finish为完成队列的头指针,ready为就绪队列的头指针,tail为循环轮转法中的就绪队列的尾指针。因为每一时刻,CPU只能运行一个进程,所以运行队列只有一个run指针指向当前运行的进程。考虑到处理的方便,将它们设为全局变量。

(1)priority()优先调度算法

在prioyity()中,进程每执行一次,优先数减1(自定),CPU时间数加1,进程还需要的时间数减1,。如果进程所需的时间为0,说明进程运行完毕,将其状态变为完成状态“F”,将此PCB插入到完成队列中,程序设计插入在完成队列的头。此时就绪队列不空的话。调用函数firstin(),将就绪队列中的第一个PCB变为运行状态。如果进程没有完成,则将其优先数和就绪队列中第一个PCB的优先数作比较,如果小,则将其变为就绪态,调用insert1()函数按照优先数插入到就绪队列中,调用firstin()函数将就绪队列中的第一个PCB变为运行态投入运行,即将优先级别高的进程投入运行,保证优先数高的优先调用,重复上述过程,直到就绪队列为空,所有进程成为完成态为止。

(2)round()时间片轮转算法

在round()中,采用固定的时间片,时间片数设为2,进程每执行一次,计数器加1,CPU时间片数加1,进程还需等待的时间片减1,如果进程所需要的时间为0,说明进程运行完毕,将其状态变为完成状态“F”,将此PCB插入到完成队列中,程序设计插入在完成队列的头。如果进程没有完成,而计数器等于固定时间片2,即到时间了,则将其变为就绪态插入到就绪队列的队尾,同时计数器清零,等待再次轮转到时调用。此时如果就绪队列不空的话,调用函数firstin(),将就绪队列的第一个PCB变为运行态,重复上述过程,知道就绪队列为空,所有进程成为完成态为止。

(3)main()主函数

用switch()选择语句来实现选用的调度算法,然后输入进程数目,根据选用的调度算法调用相应的函数创建进程和执行调度算法。

(4)create1()、create2()创建进程函数

创建进程函数的功能既创建进程控制块(PCB),并将此PCB链入就绪队列中。

create1()是按照优先数调度算法创建进程,用户输入进程标识符na以及进程所需的时间time,因为是用链表,所以申请空间存放进程PCB信息,进程的初始状态设定为“W”(就绪状态),优先数为随机数。将每个进程的PCB调用函数insert1()按照优先数大小从高到低排到就绪队列中。

create2()是按照时间片轮转调度算法创建进程,用户输入进程标识符na以及进程所需的时间time,申请空间存放进程PCB的信息,进程的初始状态设为“W”(就绪状态),时间片数设为2,统计运行所用的时间片的计数器变量count初值为0,调用函数insret2()将每个进程PCB按照输入的先后顺序插入到就绪队列的末尾。就绪队列创建好后,将队列中的第一个PCB变为运行态“R”,将run指针指向它,ready指针后移,作为就绪队列的新头指针,然后调用算法,注意每一时刻只能有一个进程处于运行态。

(5)insert1()、insert2()插入函数

这两个函数完成就绪队列的建立和管理。

insert1()的功能是将还未完成且优先数小于其他进程的PCB按进程优先数的顺序插入到就绪队列中,这个函数主要考虑插入位置。

insert2()是轮转法用的函数,功能是将执行了一个时间片且还未完成的进程的PCB插入到就绪队列的对尾,这个算法比较简单,只需改变尾指针。

3.2设计五:磁盘调度管理

设定开始磁道号寻道范围,依据起始扫描磁道号和最大磁道号数,随机产生要进行寻道的磁道号序列。选择磁盘调度算法,显示该算法的磁道访问顺序,计算出移动的磁道总数和平均寻道总数。

(1)SCAN()扫描算法

在SCAN()中,调用GetNum函数产生随机磁道号序列。通过控制while语句的执行,使一定要使当前磁道向内向外都要扫描到。用for()循环寻找与当前磁道号最短寻道的时间的磁道号。用if(DiscLine[h]>=Han)判断磁道的移动方向,即是由里向外还是由外向里,然后扫面,保证所有磁道都扫描到。

(2)CSCAN()循环扫描算法

在CSCAN()中,首先规定磁头由内向外单方向移动。

调用GetNum函数产生随机磁道号序列,然后先从初始磁道号开始,由内向外搜索离当前磁道最近的磁道号。当磁头移到最外的磁道并访问后,磁头立即返回到最里的欲访问的磁道,亦即将最小磁道号紧接着最大磁道号构成循环,进行循环扫描。

(3)PaiXu()排序函数

使用这个函数功能完成对两个算法的移动磁道距离比较和排序。在SCAN()和CSCAN()算法中就定义其排序号为2和3。

采用冒泡排序法对移动距离大小排序,排完后则执行每个算法的排序。

(4)GetNum()随机生成磁道号序列函数

srand函数在stdlib.h头文件中,time函数在time.h头文件中。srand一般与rand函数配合生成随机数据。srand(time(NULL)),可以为rand函数提供不同的种子值,进而产生不同的随机数序列。srand((unsigned)(time(NULL)))产生随机数。再通过for循环调用rand函数输出成随机序列。

(5)main()主函数

用switch()选择语句来实现选用的调度算法,然后输入初始磁道号和范围,根据选用的调度算法调用相应的函数执行调度算法。

4.算法分析

4.1设计一:进程调度

4.1.1最高优先级优先算法

就绪进程获得CPU后都只能运行一个时间片,用已占用CPU时间加1来表示。

如果运行一个时间片后,进程的已占用CPU时间已达到所需要的运行时间,则撤销该进程,如果运行一个时间片后进程的已占用CPU时间还未达到所需要的运行时间,也即进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后把它插入就绪队列等待CPU。

每进行一次调度程序都打印一次运行进程、就绪队列以及各个进程的PCB,以便进行检查。

重复以上过程,直到所有进程都完成为止。

4.1.2时间片轮转调度算法

时间片轮转算法是将所有进程按先来先服务的规则排成一个队列,把CPU分配给就绪队列的队首进程,并规定它执行一定时间,称此时间间隔为时间片。当时间片完时,剥夺该进程的执行,将它送至就绪队列的末尾,并把处理机分配给就绪队列的新队首进程,同样也让它执行一个时间片。这样,就绪队列中的所有进程均可获得一个时间片的处理机运行,知道所有进程全部执行完毕。

4.2设计五:磁盘调度管理

4.2.1扫描算法SCAN

SCAN算法不仅考虑到欲访问的磁道与当前磁道间的距离,更优先考虑的是磁头当前的移动方向。例如,当磁头正在自里向外移动时,SCAN算法所考虑的下一个访问对象,应是其欲访问的磁道既在当前磁道之外,又是距离最近的。这样自里向外地访问,直至再无更外的磁道需要访问时,才将磁臂换向为自外向里移动。

4.2.2循环扫描算法CSCAN

CSCAN算法规定磁头单向移动,例如,只是自里向外移动,当磁头移到最外的磁道并访问后,磁头立即返回到最里的欲访问的磁道,亦即将最小磁道号紧接着最大磁道号构成循环,进行循环扫描。

5.核心代码

5.1设计一:进程调度

5.1.1进程控制块结构

typedef struct node

{

    charname[10];   //进程标识符

    intprio;   //进程优先数

    intround;   //进程时间轮转时间片

    intcputime;   //进程占用CPU时间

    intneedtime;    //进程到完成还要的时间

    intcount;    //计数器

    charstate;   //进程的状态

    structnode *next;   //链指针

    intcometime;

}PCB;

5.1.2 create1()、create2()创建进程函数

void create1(char alg)  //优先数创建初始PCB信息

{

    PCB*p;

    inti,time;

    intd;

    charna[10];

    ready=NULL;//就绪队列头指针

    finish=NULL;  //完成队列头指针

    run=NULL;//运行队列头指针

    printf("请输入进程的名字和运行所需要的时间和到达时间\n"); //输入进程标识和所需时间创建PCB

        for(i=1;i<=N;i++)

   {

            p=(PCB*)malloc(sizeof(PCB));

            scanf("%s",na);

            scanf("%d",&time);

            scanf("%d",&d);

            strcpy(p->name,na);

            p->cputime=0;

            p->needtime=time;

            p->cometime=d;

            p->state='W';

            p->prio=50-time;

        if(ready!=NULL)//就绪队列不空则调用插入函数插入

            insert1(p);

        else

       {

            p->next=ready;//创建就绪队列的第一个PCB

            ready=p;

       }

   }

        voidclrscr(void);

        printf("                   最高优先级优先算法模拟输出结果:\n");

    printf("*******************************************************************\n");

        prt(alg);  //输出进程PCB信息

        run=ready;//将就绪队列的第一个进程投入运行

        ready=ready->next;

        run->state='R';

}

 

void create2(char alg)  //轮转法创建进程PCB

{

    PCB*p;

    intd;

    inti,time;

    charna[10];

    ready=NULL;

    finish=NULL;

    run=NULL;

    printf("请输入进程的名字和运行所需要的时间和到达时间\n");

        for(i=1;i<=N;i++)

   {

            p=(PCB*)malloc(sizeof(PCB));

            scanf("%s",na);

            scanf("%d",&time);

            scanf("%d",&d);

            strcpy(p->name,na);

            p->cputime=0;

            p->needtime=time;

            p->cometime=d;

            p->count=0;//计数器

            p->state='W';

            p->round=2;  //时间片

        if(ready!=NULL)

            insert2(p);

        else

       {

            p->next=ready;

            ready=p;

            tail=p;

       }

   }

        voidclrscr(void);

        printf("                   时间片轮转法模拟输出结果:\n");

    printf("********************************************************************\n");

        prt(alg);   //输出进程PCB信息

        run=ready;  //将就绪队列的第一个进程投入运行

        ready=ready->next;

        run->state='R';

}

5.1.3 insert1()、insert2()插入函数

//优先数的插入算法

void insert1(PCB *q)

{

        PCB*p1,*s,*r;

        intb;

        s=q;  //待插入的PCB指针

        p1=ready;//就绪队列头指针

        r=p1;//r做p1的前驱指针

        b=1;

  while((p1!=NULL)&&b)  //根据优先数确定插入位置

     if(p1->prio>=s->prio)

     {

        r=p1;

        p1=p1->next;

     }

     else

        b=0;

        if(r!=p1)  //如果条件成立说明插入在r与p1之间

   {

            r->next=s;

            s->next=p1;

   }

        else

   {

            s->next=p1;  //否则插入在就绪队列的头

            ready=s;

   }

}

 

//轮转法插入算法

void insert2(PCB *p2)

{

  tail->next=p2;  //将新的PCB插入在当前就绪队列的尾

  tail=p2;

  p2->next=NULL;

}

5.1.4最高优先级优先和时间片轮转调度算法

//最高优先级优先算法

void priority(char alg)

{

  while(run!=NULL)  //当运行队列不空时,有进程正在运行

   {

     run->cputime=run->cputime+1;

     run->needtime=run->needtime-1;

     run->prio=run->prio-1; //每运行一次优先数降低1个单位

     if(run->needtime==0)  //如所需时间为0将其插入完成队列

     {

    run->next=finish;

    finish=run;

    run->state='F';  //置状态为完成态

    run=NULL;  //运行队列头指针为空

    if(ready!=NULL) //如果就绪队列不空

       firstin(); //将就绪对列的第一个进程投入运行

     }

     else //没有运行完同时优先数不是最大,则将其变为就绪态插入到就绪队列

    if((ready!=NULL)&&(run->prio<ready->prio))

    {

       run->state='W';

       insert1(run);

       firstin(); //将就绪队列的第一个进程投入运行

    }

     prt(alg); //输出进程PCB信息

   }

}

 

//时间片轮转调度算法

void roundrun(char alg)

  while(run!=NULL)

   {

     run->cputime=run->cputime+1;

     run->needtime=run->needtime-1;

     run->count=run->count+1;

     if(run->needtime==0)  //运行完将其变为完成态,插入完成队列

     {

    run->next=finish;

    finish=run;

    run->state='F';

    run=NULL;

    if(ready!=NULL)

       firstin(); //就绪对列不空,将第一个进程投入运行

     }

     else

    if(run->count==run->round) //如果时间片到

    {

       run->count=0;  //计数器置0/

       if(ready!=NULL) //如就绪队列不空

       {

          run->state='W'; //将进程插入到就绪队列中等待轮转

          insert2(run);

          firstin(); //将就绪对列的第一个进程投入运行

       }

    }

        prt(alg);//输出进程信息

   }

}

5.2设计五:磁盘调度管理

5.2.1 GetNum()随机生成磁道号序列函数

void GetNum(intDiscL[])

{

    intj;

    srand((unsigned)(time(NULL)));

   for (j=0; j<10; j++)

    {

        DiscL[j]=rand()%Limit;    //设定开始磁道号寻道范围为0~200

       printf("%d ",DiscL[j]);

    }

    printf("\n");

}

5.2.2 PaiXu()寻道长度排序函数

void PaiXu()

{

    inti,j,Temp;

    for(i=0;i<4;i++)

    {

        for(j=0;j<3;j++)

        {

            if(Best[j][1]>Best[j+1][1])  //如果前一个算法的移动磁道距离大于后一个移动磁道数,执行下面语句

            {

               Temp=Best[j+1][1];    //从这起下三行执行冒泡法将移动距离大小排序,排完后则执行每个算法的排序

                Best[j+1][1]=Best[j][1];  

                Best[j][1]=Temp;

                Temp=Best[j+1][0];  //将每个算法的序号用冒泡法排序

                Best[j+1][0]=Best[j][0];

                Best[j][0]=Temp;

            }

        }

    }

}

5.2.3扫描算法(SCAN)和循环扫描算法(CSCAN)

//扫描算法(SCAN)

int SCAN(int Han,int x,int y)

{   

    intj,n,k,h,m,All;

    intt=0;

    intTemp;

    intMin;

    intOrder;

    intDiscLine[10];   //声明准备要生成的随机磁道号序列的数组

    printf("\n随机磁道号序列为:");

    GetNum(DiscLine);

    Order=1;

    k=y;

    m=2;  //控制while语句的执行,即是一定要使当前磁道向内向外都要扫描到

    All=0;  //统计全部的磁道数变量  

    printf("\n按照SCAN算法磁道的访问顺序为:");

    for(j=x;j<=y;j++)  //寻找与当前磁道号最短寻道的时间的磁道号

    { 

        if(DiscLine[j]>Han) //如果第一个随机生成的磁道号大于当前的磁道号,执行下一句  

            Temp=DiscLine[j]-Han;  //求出临时的移动距离

        else  

            Temp=Han-DiscLine[j];  //求出临时的移动距离 

        if(Temp<Min)

        {  

            Min=Temp;  //Temp临时值赋予Min 

            h=j;   //把最近当前磁道号的数组下标赋予h 

        }

    }

    All=All+Min;     

    printf("%d",DiscLine[h]);

    if(DiscLine[h]>=Han)

    {  //判断磁道的移动方向,即是由里向外还是由外向里 

        Order=0; 

        t=1;

    }

    Han=DiscLine[h];

    DelInq(DiscLine,h,k);  //每个磁道数向前移动一位

    k--;

    while(m>0) 

    { 

        if(Order==1)  //order是判断磁盘扫描的方向标签,order是1的话,磁道向内移动

        { 

            for(j=x;j<=y;j++)    

            {   

                h=-1;

                Min=64000; 

                for(n=x;n<=k;n++)  //判断离当前磁道最近的磁道号  

                {   

                   if(DiscLine[n]<=Han)  

                   {    

                       Temp=Han-DiscLine[n];  

                       if(Temp<Min)   

                       {    

                           Min=Temp;  //Temp临时值赋予Min       

                           h=n;  //把最近当前磁道号的数组下标赋予h  

                       }   

                   }  

                }  

                if(h!=-1) 

                {   

                   All=All+Min;  //叠加移动距离    

                   printf("%d",DiscLine[h]);   

                   Han=DiscLine[h];//最近的磁道号作为当前磁道 

                   DelInq(DiscLine,h,k);  

                   k--;   

                }  

            } 

            Order=0;  //当完成向内的移动,order赋予0,执行else语句,使磁道向外移动   

            m--;  //向内完成一次,m减一次,保证while循环执行两次

        }

        else  //order是0的话,磁道向外移动 

        { 

            for(j=x;j<=y;j++) 

            {   

                h=-1;

                Min=64000; 

                for(n=x;n<=k;n++)  //判断离当前磁道最近的磁道号 

                {    

                   if(DiscLine[n]>=Han)  

                   {    

                       Temp=DiscLine[n]-Han;             

                       if(Temp<Min)    

                       {     

                           Min=Temp;   //Temp临时值赋予Min       

                           h=n;  //把最近当前磁道号的数组下标赋予h  

                       }   

                   } 

                }  

                if(h!=-1)   

                {   

                   All=All+Min;  //叠加移动距离  

                   printf("%d",DiscLine[h]);  

                   Han=DiscLine[h];  //最近的磁道号作为当前磁道  

                   DelInq(DiscLine,h,k);    

                   k--;  

                }  

            } 

            Order=1; //当完成向外的移动,order赋予1,执行else语句,使磁道向内移动

            m--;   //向内完成一次,m减一次,保证while循环执行两次 

        }

    }

    NAll=NAll+All;

    if((y-x)>5)

    { 

        Best[Jage][1]=All;//Best[][1]存放移动磁道数

        Best[Jage][0]=2;//Best[][0]存放算法的序号为:2

        Jage++;//排序序号加1 

        Aver=((float)All)/10;//求平均寻道次数

        printf("\n移动磁道数:< %d > ",All); 

        printf("\n平均寻道长度:*%0.2f* ",Aver);

    }

    if(t==1)

        printf("\n磁道由内向外移动");

    else

        printf("\n磁道由外向内移动");

    return(Han);

}

 

//循环扫描算法(CSCAN)

void CSCAN(int Han)

{

    printf("\n注:规定磁头由内向外单方向移动。");

    intj,h,n,Temp,m,k,All,Last,i;

    intMin;

    inttmp=0; m=2; k=9; All=0;   //统计全部的磁道数变量

    intDiscLine[10];   //声明准备要生成的随机磁道号序列的数组

    printf("\n随机磁道号序列为:");

    GetNum(DiscLine);

    Last=Han;

    printf("\n按照CSCAN算法磁道的访问顺序为:");

    while(k>=0)

    {

        for(j=0;j<=9;j++)  //从当前磁道号开始,由内向外搜索离当前磁道最近的磁道号

        {  

            h=-1;

            Min=64000;

            for(n=0;n<=k;n++)

            {   

                if(DiscLine[n]>=Han) 

                {    

                   Temp=DiscLine[n]-Han;    

                   if(Temp<Min)  

                   {     

                       Min=Temp;     

                       h=n;   

                   }  

                } 

            }  

            if(h!=-1) 

            {  

                All=All+Min;  //统计一共移动的距离   

                printf("%d",DiscLine[h]);  

                Han=DiscLine[h]; 

                Last=DiscLine[h];  

                DelInq(DiscLine,h,k); 

                k--; 

            }

        }

        if(k>=0)

        {

            tmp=DiscLine[0];

            for(i=0;i<k;i++)//算出剩下磁道号的最小值  

            {    

                if(tmp>DiscLine[i])

                   tmp=DiscLine[i];  

            } 

            Han=tmp;//把最小的磁道号赋给Han 

            Temp=Last-tmp;//求出最大磁道号和最小磁道号的距离差  

            All=All+Temp;

        }

    }

    Best[Jage][1]=All;//Best[][1]存放移动磁道数

    Best[Jage][0]=3;//Best[][0]存放算法的序号为:3

    Jage++;//排序序号加1

    Aver=((float)All)/10;//求平均寻道次数

    printf("\n移动磁道数:< %d > ",All);

    printf("\n平均寻道长度:*%0.2f* ",Aver);

}


 

6.测试数据或截图

6.1设计一:进程调度

6.1.1最高优先级优先算法

 

图6-1最高优先级优先算法

6.1.2时间片轮转调度算法

图6-2时间片轮转调度算法

6.2设计五:磁盘调度管理

6.2.1扫描算法SCAN

图6-3扫描算法SCAN

6.2.2循环扫描算法CSCAN

图6-4循环扫描算法CSCAN

6.2.3各类算法性能比较


图6-5各类算法性能比较

 


 

7.心得体会

这次为期三周的实习,真真正正让我体会到了代码的无限乐趣!

原本打算用这学期新学的java来实现进程调度和磁盘调度,经过不断地磨合修改代码,从课本学习对照,上网查资料,第一周已经过了四天,而我得出了我的进程调度的简化版本,真的很满足当时。可是后来发现磁盘调度在java上有很多地方不熟悉,而且陆陆续续出了很多的问题却找不到解决办法,只好还是从新用更熟悉的c语言来打。在磁盘调度的随机数产生随机序列上遇到了问题,后来使用stdlib.h和time.h头文件中的srand函数和rand函数的配合与time函数解决了这个问题。刚开始先从先来先服务(FCFS)算法开始,陆陆续续攻克很多难关完成了进程调度和磁盘调度等等的问题。最终把界面优化美化后看起来很舒服。

在实习期间,通过和舍友的讨论和上网学习,真正的学到了很多东西。从刚开始的为了完成任务而学习变成了因为兴趣而学习,养成了很好的学习习惯。这次实习令人很满足,也很令人回味。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值