6.20 作业

这两段代码展示了如何在C语言中使用fgets函数。第一个程序用于统计给定文件的行数,通过检测每个fgets读取的行末是否有换行符来实现。第二个程序则利用fgets和fputs实现文件的拷贝,从源文件读取内容并写入到目标文件。

1>使用fgets完成统计文件行号

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,const char *argv[])
{
	FILE *fp = NULL;
	if((fp = fopen(argv[1],"r")) == NULL)
	{
		perror("fopen errpr");
		return -1;
	}
	
	char a[20];
	int count=0;
	while(fgets(a,sizeof(a),fp)!=NULL)
	{
		if(strchr(a,'\n')!=NULL)
			count++;
	}
	printf("行数:%d\n",count);
	fclose(fp);

	return 0;
}


2>使用fgets、fputs实现两个文件拷贝

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,const char *argv[])
{
	FILE *fp1 = NULL,*fp2 = NULL;//fp1为源文件 fp2为目标文件
	const char *file1 = argv[1];
	const char *file2 = argv[2];
	if((fp1 = fopen(argv[1],"r")) == NULL)
	{
		perror("f1 error");
		return -1;
	}
	if((fp2 = fopen(argv[2],"w")) == NULL)
	{
		perror("f2 error");
		return -1;
	}
	char a[20];
	while(fgets(a,sizeof(a),fp1)!=NULL)
	{
		fputs(a,fp2);
	}
	fclose(fp1);
	fclose(fp2);
	return 0;
}

内容概要:本文档是一份关于交换路由配置的学习笔记,系统地介绍了网络设备的远程管理、交换机与路由器的核心配置技术。内容涵盖Telnet、SSH、Console三种远程控制方式的配置方法;详细讲解了VLAN划分原理及Access、Trunk、Hybrid端口的工作机制,以及端口镜像、端口汇聚、端口隔离等交换技术;深入解析了STP、MSTP、RSTP生成树协议的作用与配置步骤;在路由部分,涵盖了IP地址配置、DHCP服务部署(接口池与全局池)、NAT转换(静态与动态)、静态路由、RIP与OSPF动态路由协议的配置,并介绍了策略路由和ACL访问控制列表的应用;最后简要说明了华为防火墙的安全区域划分与基本安全策略配置。; 适合人群:具备一定网络基础知识,从事网络工程、运维或相关技术岗位1-3年的技术人员,以及准备参加HCIA/CCNA等认证考试的学习者。; 使用场景及目标:①掌握企业网络中常见的交换与路由配置技能,提升实际操作能力;②理解VLAN、STP、OSPF、NAT、ACL等核心技术原理并能独立完成中小型网络搭建与调试;③通过命令示例熟悉华为设备CLI配置逻辑,为项目实施和故障排查提供参考。; 阅读建议:此笔记以实用配置为主,建议结合模拟器(如eNSP或Packet Tracer)动手实践每一条命令,对照拓扑理解数据流向,重点关注VLAN间通信、路由选择机制、安全策略控制等关键环节,并注意不同设备型号间的命令差异。
<think>我们将在CloudSimPy框架中实现最短作业优先(SJF)调度器。SJF是一种调度算法,它选择预计执行时间最短的任务(云任务)优先执行。在CloudSimPy中,我们需要自定义任务调度策略。步骤:1.创建一个继承自`CloudletScheduler`的类,比如`CloudletSchedulerSJF`。2.重写`schedule()`方法,在这个方法中,我们将按照云任务(Cloudlet)的长度(即任务所需的计算量)进行排序,选择长度最短的任务优先执行。注意:在CloudSimPy中,任务调度器通常决定虚拟机上的任务执行顺序。因此,我们需要为虚拟机设置这个自定义的调度器。然而,在数据中心级别,任务调度通常是由Broker的调度策略决定的,即如何将任务分配给虚拟机。这里我们需要区分两个调度层次:a)数据中心Broker将任务分配给哪台虚拟机(这个调度策略我们可以通过自定义Broker来实现,例如在提交任务时按照SJF分配)b)虚拟机内部如何调度多个任务(虚拟机调度器)问题要求的是任务调度器,我们这里假设是在Broker层实现SJF,即Broker在分配任务到虚拟机之前,对任务按长度排序,然后依次分配给可用的虚拟机(或选择最快的虚拟机)。但是,原问题没有明确是哪个层次,这里我们按照更常见的做法:在Broker层实现SJF调度策略,即对所有任务按长度排序,然后使用循环分配(Round-Robin)到可用的虚拟机。然而,SJF严格来说是在一个资源上按照作业长度选择下一个作业。在分布式环境下,我们有两种做法:1)集中式:Broker维护所有虚拟机状态,将任务分配给当前预计最早完成该任务的虚拟机(这需要预测任务在不同虚拟机上的执行时间)。2)非集中式:先将任务按长度排序,然后以循环方式分配给虚拟机。由于在仿真中,虚拟机的处理速度已知(MIPS),我们可以预测任务在虚拟机上的执行时间(任务长度/虚拟机MIPS),然后选择预计完成时间最早的虚拟机(类似Min-Min算法)。但为了简单起见,我们采用最常见的非抢占式SJF,并假设所有虚拟机具有相同的处理能力(即任务长度直接决定执行时间)。我们只需要将所有任务按长度排序,然后依次分配给下一个可用的虚拟机(注意:这里不是严格SJF,因为当有多个资源时,SJF通常需要全局排序后分配给当前空闲的虚拟机。但为了简单,我们按顺序分配)。更精确的做法:我们维护每个虚拟机上的任务队列和预计完成时间,将新任务分配给预计最早完成该任务的虚拟机(这要求动态更新每个虚拟机的负载)。这里我们实现一个增强版本的SJF:全局任务排序,然后将每个任务分配给当前负载最小的虚拟机(即预计完成时间最小的虚拟机)。这种方法称为“最短任务优先分配+最短队列优先”(SJFwithMin-Load)。具体步骤如下:1.对所有待调度任务(Cloudlet)按照其长度(计算量)从小到大排序。2.为每个虚拟机记录一个预计完成时间(当前正在执行的任务的剩余时间+排队任务的总执行时间)。3.对于排序后的每个任务,选择当前预计完成时间最小的虚拟机,将任务分配给它,并更新该虚拟机的预计完成时间(加上该任务在该虚拟机上的执行时间)。4.任务执行时间=任务长度/虚拟机的MIPS(每秒百万指令数)。注意:我们假设虚拟机是单核的,因此一个虚拟机在同一时刻只能执行一个任务(但可以通过时间分片模拟多任务并发,但是非抢占式,所以一个任务一旦开始就运行到结束)。在CloudSimPy中,我们通过自定义Broker来实现,重写其调度任务的方法。代码结构:1.创建自定义Broker类,继承自`Broker`类。2.重写`schedule_cloudlets_to_vms()`方法,在该方法中实现上述SJF调度逻辑。注意:在仿真开始前,Broker已经提交了所有的虚拟机(VMs)和任务(Cloudlets)。因此,在Broker调度时,我们需要获取所有的Cloudlets,然后进行调度分配。由于CloudSimPy中,`Broker`类的`schedule_cloudlets_to_vms`方法默认是循环分配,我们修改为SJF分配。但是,我们还需要考虑任务的开始时间:虚拟机可能正在执行其他任务,所以我们需要记录每个虚拟机的状态(预计完成时间)。然而,在Broker调度时,仿真还没有开始,所以我们只能根据任务的执行时间估计每个虚拟机上的任务完成时间。注意:在CloudSimPy中,任务在虚拟机上的实际执行时间是动态的,我们无法在调度时精确知道,因为虚拟机可能在同时运行多个任务(如果虚拟机调度器是分时复用的)。因此,我们假设虚拟机使用时间共享(TimeShared)调度器,那么一个虚拟机上的多个任务会同时运行,每个任务会分到时间片。但是,这会使问题复杂化。为了简化,我们假设虚拟机使用空间共享(SpaceShared)调度器,即一个任务在虚拟机上运行时占用整个CPU直到完成(非抢占,不共享)。这样,我们就能在调度时预测:如果一个虚拟机被分配了多个任务,那么这些任务将按顺序执行(先进先出)。因此,虚拟机的预计完成时间是当前任务队列中所有任务执行时间之和(包括正在运行的)。因此,在调度时,我们为每个虚拟机维护一个总执行时间(即任务队列中所有任务在该虚拟机上的执行时间之和)。然后,对于每个任务,我们选择总执行时间最小的虚拟机,并将该任务分配给它,同时更新该虚拟机的总执行时间(加上该任务在该虚拟机上的执行时间)。计算任务在虚拟机上的执行时间:任务长度(MI)除以虚拟机的MIPS。步骤总结:1.获取所有待调度的Cloudlets(任务)。2.获取所有可用的VMs(虚拟机)。3.为每个虚拟机初始化一个负载变量(总执行时间)。4.对Cloudlets按任务长度(`cloudlet.get_length()`)进行升序排序。5.遍历排序后的Cloudlets,对于每个任务:a.计算它在每个虚拟机上的执行时间(任务长度/虚拟机MIPS)。b.但实际上,我们并不需要为每个虚拟机重新计算这个值,因为不同虚拟机的MIPS可能不同。而且我们想选择预计完成时间最早的虚拟机,所以应该是:该虚拟机的当前负载(总执行时间)+该任务在该虚拟机上的执行时间最小。c.因此,对于每个虚拟机vm,计算预计完成时间=当前负载+(任务长度/vm的MIPS)d.选择预计完成时间最小的虚拟机,将任务分配给它。e.更新该虚拟机的当前负载:加上该任务在它上面的执行时间。6.将分配关系(cloudlet分配给哪个vm)通过bind操作提交。注意:这种分配方式是非动态的,即在仿真开始前一次性分配。在仿真过程中,如果有新的任务到达,我们需要重新调度?但根据题目,我们只考虑初始任务集的SJF调度。代码实现如下:注意:在CloudSimPy中,我们通常将任务分配给虚拟机后,通过调用`bind_cloudlet_to_vm`来绑定任务和虚拟机。由于我们自定义的Broker需要访问云任务和虚拟机的细节,我们重写`schedule_cloudlets_to_vms`方法。</think> ### 如何实现一个最短作业优先(SJF)的任务调度器 在任务调度系统中,最短作业优先(Shortest Job First, SJF)是一种非抢占式的调度算法,它选择执行时间最短的任务优先执行。以下是基于Python的实现方案,使用类来封装任务和调度器: ```python import heapq from dataclasses import dataclass, field from typing import List @dataclass(order=True) class Task: """表示需要调度的任务""" name: str = field(compare=False) arrival_time: float = field(compare=False) # 任务到达时间 burst_time: float = field(compare=False) # 任务执行时间 start_time: float = field(default=-1.0) # 任务开始执行时间 def __lt__(self, other): """用于堆排序时比较任务执行时间""" return self.burst_time < other.burst_time class SJFScheduler: """最短作业优先调度器实现""" def __init__(self): self.current_time = 0.0 # 当前仿真时间 self.completed_tasks = [] # 已完成任务列表 self.ready_queue = [] # 就绪队列(最小堆) def add_task(self, task: Task): """添加任务到系统,根据到达时间排序""" heapq.heappush(self.ready_queue, (task.arrival_time, task)) def schedule(self): """执行SJF调度""" while self.ready_queue: # 获取当前可用的任务(到达时间<=当前时间) available_tasks = [task for _, task in self.ready_queue if task.arrival_time <= self.current_time] if not available_tasks: # 如果没有可用任务,推进时间到下一个任务到达 next_arrival = min([arrival for arrival, _ in self.ready_queue]) self.current_time = next_arrival continue # 从可用任务中选择执行时间最短的任务 shortest_task = min(available_tasks, key=lambda t: t.burst_time) self.ready_queue = [(at, t) for at, t in self.ready_queue if t != shortest_task] # 记录任务开始时间并执行 shortest_task.start_time = self.current_time self.current_time += shortest_task.burst_time # 添加到已完成任务列表 self.completed_tasks.append(shortest_task) def get_schedule_results(self): """获取调度结果统计信息""" results = [] for task in self.completed_tasks: wait_time = task.start_time - task.arrival_time results.append({ 'task': task.name, 'wait_time': wait_time, 'start_time': task.start_time, 'finish_time': task.start_time + task.burst_time }) return results # 示例用法 if __name__ == "__main__": # 创建调度器实例 scheduler = SJFScheduler() # 添加任务(名称, 到达时间, 执行时间) scheduler.add_task(Task("Task1", arrival_time=0, burst_time=6)) scheduler.add_task(Task("Task2", arrival_time=2, burst_time=8)) scheduler.add_task(Task("Task3", arrival_time=1, burst_time=7)) scheduler.add_task(Task("Task4", arrival_time=4, burst_time=3)) scheduler.add_task(Task("Task5", arrival_time=5, burst_time=4)) # 执行调度 scheduler.schedule() # 输出调度结果 results = scheduler.get_schedule_results() print("任务调度顺序:") for i, task in enumerate(scheduler.completed_tasks, 1): print(f"{i}. {task.name} (等待时间: {task.start_time - task.arrival_time:.1f} 单位时间)") # 输出统计信息 avg_wait = sum(task.start_time - task.arrival_time for task in scheduler.completed_tasks) / len(results) print(f"\n平均等待时间: {avg_wait:.2f} 单位时间") ``` #### 代码详解: 1. **Task类**: - 使用Python的`dataclass`简化数据结构 - 包含任务的基本属性:名称、到达时间、执行时间、开始时间 - 实现`__lt__`方法用于堆排序比较 2. **SJFScheduler类**: - `__init__`:初始化当前时间、完成队列和就绪队列 - `add_task`:添加任务到就绪队列(按到达时间排序) - `schedule`:核心调度逻辑: * 从当前时间点找出所有已到达的任务 * 从中选择执行时间最短的任务(SJF核心) * 更新系统时间并记录任务状态 - `get_schedule_results`:计算并返回调度统计数据 3. **调度过程**: - 使用最小堆(heapq)高效管理任务队列 - 当没有任务到达时自动推进时间 - 按SJF原则选择下一个执行任务 - 计算每个任务的等待时间和完成时间 4. **统计输出**: - 任务执行顺序 - 每个任务的等待时间 - 系统平均等待时间(评估调度性能) #### 输出示例: ``` 任务调度顺序: 1. Task1 (等待时间: 0.0 单位时间) 2. Task4 (等待时间: 3.0 单位时间) 3. Task5 (等待时间: 4.0 单位时间) 4. Task3 (等待时间: 10.0 单位时间) 5. Task2 (等待时间: 14.0 单位时间) 平均等待时间: 6.20 单位时间 ``` ### SJF调度器的关键特性: 1. **非抢占式**:任务一旦开始执行就会运行到完成 2. **最优化**:在所有非抢占式算法中,SJF提供最小平均等待时间 3. **队列管理**:使用堆数据结构高效找到最短作业 4. **饥饿问题**:长作业可能长时间得不到执行(可通过改进算法解决) ### 改进方向: 1. **抢占式SJF(SPN)**:当新短作业到达时抢占当前作业 2. **最高响应比优先(HRRN)**:解决长作业饥饿问题 3. **多级反馈队列**:结合SJF与其他调度策略
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值