操作系统导论-第四章作业(待更)

news2024/11/29 20:57:08

一、进程

进程就是运行中的程序,程序本身是没有生命周期的,它只是存储在磁盘上的一些指令(或者一些静态数据),操作系统将这些指令和数据加载到内存中,使其运行起来。

1.1 虚拟化CPU技术

根据我们平时使用计算机的经验表明,计算机往往可以同时运行多个进程,实际上,一个正常的系统可能会有上百个进程同时在运行,但物理CPU是少量的,那么操作系统是如何提供几乎有无数个CPU的假象的呢——这就是虚拟化CPU技术。

如何实现虚拟化CPU?
操作系统通过让一个进程只运行一个时间片(毫秒级),然后切换到其他进程的做法,造成了有多个CPU的假象,这就是常说的时分共享CPU技术。
显然,这会造成性能损失,因为CPU必须被多个进程共享,每个进程的运行就会慢一点。

补充知识:
时分共享是操作系统共享资源的最基本的技术之一,允许资源由一个实体使用一小段时间,然后切换,这样循环下去,资源就可以被许多人共享。
空分共享是资源在空间上被划分给希望使用它的人,比如,磁盘空间是一个空分共享资源,一旦将块分配给文件,在用户删除文件之前,其他人不可能使用这个块空间。

1.2 进程的机器状态

进程还可以理解为操作系统为程序提供的一个抽象。对于一个进程,在任何时候,我们都可以知道它在运行过程中访问或影响的系统的不同部分,反过来说,被影响和访问的系统部分也可以用来概括该进程。

为了理解进程的构成,我们必须了解它的机器状态——程序在运行时可以读取或更新的内容。

在任意时刻,物理计算机的哪些部分对执行程序很重要?
进程的机器状态有个很重要的组成部分,就是进程的内存。指令存在在内存中,正在运行的程序读取和写入的数据也在内存中。
进程的机器状态的另一部分是寄存器。进程的许多指令明确地读取或更新寄存器。因此,他们对于执行该进程很重要。

有一些非常特殊的寄存器构成了该机器状态的一部分。例如,程序计数器(Program Counter)告诉我们程序当前正在执行哪个指令,栈指针(Stack Pointer)和相关的帧指针(Frame Pointer)用于管理函数参数栈、局部变量和返回地址。

1.3 进程API

操作系统所有的接口必须包含的内容有:

  • 创建 (Create):操作系统必须包含一些创建新进程的方法。比如,在Shell中输入命令或者双击应用图标时,所有现代操作系统都会以某种形式提供这些API。
  • 销毁 (Destory):由于存在创建进程的接口,因此操作系统还要提供强制销毁进程的接口。尽管很多进程会在运行完成后自己退出,但是,如果它们不退出,用户希望能够强制终止它们。因此停止失控进程的接口很有用。
  • 等待 (Wait):有时会有等待进程停止运行的需求,因此操作系统会提供相关接口。
  • 其他控制(Miscellaneous control):除了杀死或等待进程外,有时还可能有其他控制。比如,大多数操作系统提供某种方法来暂停进程(停止运行一段时间),然后恢复(继续运行)。
  • 状态(Statu):通常也有一些接口可以获得有关进程的状态信息,例如运行了多长时间,或者处于什么状态。

1.4 如何创建一个进程?

程序如何转化为一个进程?换个说法,操作系统是如何启动一个程序的?进程的创建实际上如何进行?

程序首先要被加载进内存

首先,程序必须被操作系统加载进内存,程序最初是以某个可执行格式驻留在磁盘上(disk,或者在某些现代系统中,在基于闪存的SSD上)。因此,将程序和静态数据加载到内存中的过程,需要操作系统从磁盘读取这些字节,并把它们放在内存的某处。

在早期的(或简单的)操作系统中,程序要全部加载进内存之后才会开始执行程序 。但是现代操作系统惰性(Lazily)执行该过程,即仅在程序执行期间需要加载的代码或数据片段,才会加载。这个惰性加载涉及到分页和交换机制,这块是内存虚拟化的内容。

为程序分配运行时内存
  • C程序用栈存放局部变量、函数参数和返回地址。操作系统也可能会用参数初始化栈,它会将参数填入main()函数,这个参数就是argc 和 argv数组。
  • 操作系统也可能为程序的堆(heap)分配一些内存,对于C程序来说,堆用于显示请求的动态分配数据。程序会通过调用malloc()来请求内存,并通过调用free()来明确地释放它。数据结构(如链表、散列表、树和其他数据结构)需要堆空间。一开始堆很小,但随着程序的运行,通过malloc()库请求更多内存,操作系统可能会参与分配更多的内存给进程。
IO设置相关工作

操作系统还要执行一些其他的初始化任务,尤其是输入输出相关的任务。比如,在UNIX系统中,默认情况下每个进程都有3个打开的文件描述符,用于标准输入、输出和错误。这些描述符让程序轻松读取来自终端的输入以及打印输出到屏幕。

启动程序

前面的工作完成之后,操作系统还有最后一项任务:启动程序,在入口处运行,即main()函数,通过跳转到main()例程,操作系统(OS)将CPU的控制权转移到新建的进程中,从而程序开始执行了。

1.5 进程状态

进程在任意时间可能会处于不同的状态,简单来讲,进程可以处于下面3种状态之一:

  • 运行 (running):在运行状态下,进程正在CPU上运行,这意味着它正在执行指令。
  • 就绪 (ready):在就绪状态下,进程已经准备好运行,但由于某种原因,操作系统选择不在此时运行
  • 阻塞 (blocked):在阻塞状态下,一个进程执行了某个操作,需要等待其它事件发生才能继续执行(比如此时程序发起IO请求,需要等待IO完成才能继续执行),这时它就会被阻塞,其它进程可以使用CPU。
状态转换

在这里插入图片描述

进程的上下文切换

操作系统是一个程序,和其他程序一样,它有一些关键的数据结构来跟踪各种相关的信息。
比如,为了跟踪每个进程的状态,操作系统可能会为所有就绪的进程保留某种进程列表,以及跟踪当前正在运行的进程的一些附加信息。操作系统还必须以某种方式跟踪被阻塞的进程。当IO事件完成时,操作系统应该确保唤醒正确的进程,让它准备好再次运行。

操作系统会追踪进程的一些重要信息。对于停止的进程,寄存器上下文将保存其寄存器的内容。当一个进程停止时,它的寄存器将被保存在这个内存位置。通过恢复这些寄存器(将它们的值放回实际的物理寄存器中),操作系统可以恢复运行该进程。这被称为上下文切换(Context Switch)。

进程除了运行、就绪和阻塞之外,还有其他一些进程可以处于的状态。有时候系统会有一个初始状态,表示进程在创建时处于的状态——新建态
另外,一个进程可以处于已退出但尚未清理的最终状态(在基于UNIX的系统中,这称为僵尸状态)。这个最终状态非常有用,因为它允许其他进程(通常是创建该进程的父进程)检查进程的返回代码,并查看感刚刚结束的进程是否成功执行(在UNIX系统中,程序成功执行返回0,否则返回非0)。完成后,父进程将进行最后一次调用(例如,wait()),以等待子进程的完成,并告诉操作系统它可以清理这个正在结束的进程的所有相关数据结构。

二、章节作业

模拟作业:模拟作业以模拟器的形式出现,你运行它以确保理解上述内容。模拟器通常是Python程序,它们让你能够生成不同的问题(使用不同的随机种子),也让程序为你解决问题,以便你检查答案。使用-h或-help参数运行任何模拟器,将提供有关模拟器所有选项的更多信息。

程序process-run.py 让你能够查看程序运行时进程状态如何改变,是在使用CPU(例如,执行相加指令)还是执行I/O(例如,向磁盘发送请求并等待它完成)。

process-run.py 代码
#! /usr/bin/python2

from __future__ import print_function
import sys
from optparse import OptionParser
import random

# to make Python2 and Python3 act the same -- how dumb
def random_seed(seed):
    try:
        random.seed(seed, version=1)
    except:
        random.seed(seed)
    return

# process switch behavior
SCHED_SWITCH_ON_IO = 'SWITCH_ON_IO'
SCHED_SWITCH_ON_END = 'SWITCH_ON_END'

# io finished behavior
IO_RUN_LATER = 'IO_RUN_LATER'
IO_RUN_IMMEDIATE = 'IO_RUN_IMMEDIATE'

# process states
STATE_RUNNING = 'RUNNING'
STATE_READY = 'READY'
STATE_DONE = 'DONE'
STATE_WAIT = 'WAITING'

# members of process structure
PROC_CODE = 'code_'
PROC_PC = 'pc_'
PROC_ID = 'pid_'
PROC_STATE = 'proc_state_'

# things a process can do
DO_COMPUTE = 'cpu'
DO_IO = 'io'
DO_IO_DONE = 'io_done'


class scheduler:
    def __init__(self, process_switch_behavior, io_done_behavior, io_length):
        # keep set of instructions for each of the processes
        self.proc_info = {}
        self.process_switch_behavior = process_switch_behavior
        self.io_done_behavior = io_done_behavior
        self.io_length = io_length
        return

    def new_process(self):
        proc_id = len(self.proc_info)
        self.proc_info[proc_id] = {}
        self.proc_info[proc_id][PROC_PC] = 0
        self.proc_info[proc_id][PROC_ID] = proc_id
        self.proc_info[proc_id][PROC_CODE] = []
        self.proc_info[proc_id][PROC_STATE] = STATE_READY
        return proc_id

    # program looks like this:
    #   c7,i,c1,i
    # which means
    #   compute for 7, then i/o, then compute for 1, then i/o
    def load_program(self, program):
        proc_id = self.new_process()
        for line in program.split(','):
            opcode = line[0]
            if opcode == 'c': # compute
                num = int(line[1:])
                for i in range(num):
                    self.proc_info[proc_id][PROC_CODE].append(DO_COMPUTE)
            elif opcode == 'i':
                self.proc_info[proc_id][PROC_CODE].append(DO_IO)
                # add one compute to HANDLE the I/O completion
                self.proc_info[proc_id][PROC_CODE].append(DO_IO_DONE)
            else:
                print('bad opcode %s (should be c or i)' % opcode)
                exit(1)
        return

    def load(self, program_description):
        proc_id = self.new_process()
        tmp = program_description.split(':')
        if len(tmp) != 2:
            print('Bad description (%s): Must be number <x:y>' % program_description)
            print('  where X is the number of instructions')
            print('  and Y is the percent change that an instruction is CPU not IO')
            exit(1)

        num_instructions, chance_cpu = int(tmp[0]), float(tmp[1])/100.0
        for i in range(num_instructions):
            if random.random() < chance_cpu:
                self.proc_info[proc_id][PROC_CODE].append(DO_COMPUTE)
            else:
                self.proc_info[proc_id][PROC_CODE].append(DO_IO)
                # add one compute to HANDLE the I/O completion
                self.proc_info[proc_id][PROC_CODE].append(DO_IO_DONE)
        return

    def move_to_ready(self, expected, pid=-1):
        if pid == -1:
            pid = self.curr_proc
        assert(self.proc_info[pid][PROC_STATE] == expected)
        self.proc_info[pid][PROC_STATE] = STATE_READY
        return

    def move_to_wait(self, expected):
        assert(self.proc_info[self.curr_proc][PROC_STATE] == expected)
        self.proc_info[self.curr_proc][PROC_STATE] = STATE_WAIT
        return

    def move_to_running(self, expected):
        assert(self.proc_info[self.curr_proc][PROC_STATE] == expected)
        self.proc_info[self.curr_proc][PROC_STATE] = STATE_RUNNING
        return

    def move_to_done(self, expected):
        assert(self.proc_info[self.curr_proc][PROC_STATE] == expected)
        self.proc_info[self.curr_proc][PROC_STATE] = STATE_DONE
        return

    def next_proc(self, pid=-1):
        if pid != -1:
            self.curr_proc = pid
            self.move_to_running(STATE_READY)
            return
        for pid in range(self.curr_proc + 1, len(self.proc_info)):
            if self.proc_info[pid][PROC_STATE] == STATE_READY:
                self.curr_proc = pid
                self.move_to_running(STATE_READY)
                return
        for pid in range(0, self.curr_proc + 1):
            if self.proc_info[pid][PROC_STATE] == STATE_READY:
                self.curr_proc = pid
                self.move_to_running(STATE_READY)
                return
        return

    def get_num_processes(self):
        return len(self.proc_info)

    def get_num_instructions(self, pid):
        return len(self.proc_info[pid][PROC_CODE])

    def get_instruction(self, pid, index):
        return self.proc_info[pid][PROC_CODE][index]

    def get_num_active(self):
        num_active = 0
        for pid in range(len(self.proc_info)):
            if self.proc_info[pid][PROC_STATE] != STATE_DONE:
                num_active += 1
        return num_active

    def get_num_runnable(self):
        num_active = 0
        for pid in range(len(self.proc_info)):
            if self.proc_info[pid][PROC_STATE] == STATE_READY or \
                   self.proc_info[pid][PROC_STATE] == STATE_RUNNING:
                num_active += 1
        return num_active

    def get_ios_in_flight(self, current_time):
        num_in_flight = 0
        for pid in range(len(self.proc_info)):
            for t in self.io_finish_times[pid]:
                if t > current_time:
                    num_in_flight += 1
        return num_in_flight

    def check_for_switch(self):
        return

    def space(self, num_columns):
        for i in range(num_columns):
            print('%10s' % ' ', end='')

    def check_if_done(self):
        if len(self.proc_info[self.curr_proc][PROC_CODE]) == 0:
            if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING:
                self.move_to_done(STATE_RUNNING)
                self.next_proc()
        return

    def run(self):
        clock_tick = 0

        if len(self.proc_info) == 0:
            return

        # track outstanding IOs, per process
        self.io_finish_times = {}
        for pid in range(len(self.proc_info)):
            self.io_finish_times[pid] = []

        # make first one active
        self.curr_proc = 0
        self.move_to_running(STATE_READY)

        # OUTPUT: headers for each column
        print('%s' % 'Time', end='') 
        for pid in range(len(self.proc_info)):
            print('%14s' % ('PID:%2d' % (pid)), end='')
        print('%14s' % 'CPU', end='')
        print('%14s' % 'IOs', end='')
        print('')

        # init statistics
        io_busy = 0
        cpu_busy = 0

        while self.get_num_active() > 0:
            clock_tick += 1

            # check for io finish
            io_done = False
            for pid in range(len(self.proc_info)):
                if clock_tick in self.io_finish_times[pid]:
                    io_done = True
                    self.move_to_ready(STATE_WAIT, pid)
                    if self.io_done_behavior == IO_RUN_IMMEDIATE:
                        # IO_RUN_IMMEDIATE
                        if self.curr_proc != pid:
                            if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING:
                                self.move_to_ready(STATE_RUNNING)
                        self.next_proc(pid)
                    else:
                        # IO_RUN_LATER
                        if self.process_switch_behavior == SCHED_SWITCH_ON_END and self.get_num_runnable() > 1:
                            # this means the process that issued the io should be run
                            self.next_proc(pid)
                        if self.get_num_runnable() == 1:
                            # this is the only thing to run: so run it
                            self.next_proc(pid)
                    self.check_if_done()
            
            # if current proc is RUNNING and has an instruction, execute it
            instruction_to_execute = ''
            if self.proc_info[self.curr_proc][PROC_STATE] == STATE_RUNNING and \
                   len(self.proc_info[self.curr_proc][PROC_CODE]) > 0:
                instruction_to_execute = self.proc_info[self.curr_proc][PROC_CODE].pop(0)
                cpu_busy += 1

            # OUTPUT: print what everyone is up to
            if io_done:
                print('%3d*' % clock_tick, end='')
            else:
                print('%3d ' % clock_tick, end='')
            for pid in range(len(self.proc_info)):
                if pid == self.curr_proc and instruction_to_execute != '':
                    print('%14s' % ('RUN:'+instruction_to_execute), end='')
                else:
                    print('%14s' % (self.proc_info[pid][PROC_STATE]), end='')

            # CPU output here: if no instruction executes, output a space, otherwise a 1 
            if instruction_to_execute == '':
                print('%14s' % ' ', end='')
            else:
                print('%14s' % '1', end='')

            # IO output here:
            num_outstanding = self.get_ios_in_flight(clock_tick)
            if num_outstanding > 0:
                print('%14s' % str(num_outstanding), end='')
                io_busy += 1
            else:
                print('%10s' % ' ', end='')
            print('')

            # if this is an IO start instruction, switch to waiting state
            # and add an io completion in the future
            if instruction_to_execute == DO_IO:
                self.move_to_wait(STATE_RUNNING)
                self.io_finish_times[self.curr_proc].append(clock_tick + self.io_length + 1)
                if self.process_switch_behavior == SCHED_SWITCH_ON_IO:
                    self.next_proc()

            # ENDCASE: check if currently running thing is out of instructions
            self.check_if_done()
        return (cpu_busy, io_busy, clock_tick)
        
#
# PARSE ARGUMENTS
#

parser = OptionParser()
parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
parser.add_option('-P', '--program', default='', help='more specific controls over programs', action='store', type='string', dest='program')
parser.add_option('-l', '--processlist', default='', help='a comma-separated list of processes to run, in the form X1:Y1,X2:Y2,... where X is the number of instructions that process should run, and Y the chances (from 0 to 100) that an instruction will use the CPU or issue an IO', action='store', type='string', dest='process_list')
parser.add_option('-L', '--iolength', default=5, help='how long an IO takes', action='store', type='int', dest='io_length')
parser.add_option('-S', '--switch', default='SWITCH_ON_IO', help='when to switch between processes: SWITCH_ON_IO, SWITCH_ON_END', action='store', type='string', dest='process_switch_behavior')
parser.add_option('-I', '--iodone', default='IO_RUN_LATER', help='type of behavior when IO ends: IO_RUN_LATER, IO_RUN_IMMEDIATE', action='store', type='string', dest='io_done_behavior')
parser.add_option('-c', help='compute answers for me', action='store_true', default=False, dest='solve')
parser.add_option('-p', '--printstats', help='print statistics at end; only useful with -c flag (otherwise stats are not printed)', action='store_true', default=False, dest='print_stats')
(options, args) = parser.parse_args()

random_seed(options.seed)

assert(options.process_switch_behavior == SCHED_SWITCH_ON_IO or options.process_switch_behavior == SCHED_SWITCH_ON_END)
assert(options.io_done_behavior == IO_RUN_IMMEDIATE or options.io_done_behavior == IO_RUN_LATER)

s = scheduler(options.process_switch_behavior, options.io_done_behavior, options.io_length)

if options.program != '':
    for p in options.program.split(':'):
        s.load_program(p)
else:
    # example process description (10:100,10:100)
    for p in options.process_list.split(','):
        s.load(p)

assert(options.io_length >= 0)

if options.solve == False:
    print('Produce a trace of what would happen when you run these processes:')
    for pid in range(s.get_num_processes()):
        print('Process %d' % pid)
        for inst in range(s.get_num_instructions(pid)):
            print('  %s' % s.get_instruction(pid, inst))
        print('')
    print('Important behaviors:')
    print('  System will switch when ', end='')
    if options.process_switch_behavior == SCHED_SWITCH_ON_IO:
        print('the current process is FINISHED or ISSUES AN IO')
    else:
        print('the current process is FINISHED')
    print('  After IOs, the process issuing the IO will ', end='')
    if options.io_done_behavior == IO_RUN_IMMEDIATE:
        print('run IMMEDIATELY')
    else:
        print('run LATER (when it is its turn)')
    print('')
    exit(0)

(cpu_busy, io_busy, clock_tick) = s.run()

if options.print_stats:
    print('')
    print('Stats: Total Time %d' % clock_tick)
    print('Stats: CPU Busy %d (%.2f%%)' % (cpu_busy, 100.0 * float(cpu_busy)/clock_tick))
    print('Stats: IO Busy  %d (%.2f%%)' % (io_busy, 100.0 * float(io_busy)/clock_tick))
    print('')

tips:第一行的代码是表示python程序所在的绝对路径,这个需要根据自己python程序所在的位置做修改。

问题
  • 1.用以下标志运行程序: ./process-run.py -l 5:100,5:100。CPU利用率(CPU使用时间的百分比)应该是多少?为什么你知道这一点?利用-c参数查看你的答案是否正确。

    运行结果截图
    在这里插入图片描述

先解释一下参数:

  • -l 表示显示进程列表,展示出所有的进程
  • 5:100 表示指定进程是"5:100",这意味着该进程由5条指令组成,并且每条指令是CPU指令的可能性是100%
    这条命令有两个5:100,表示同时运行两个进程。

答案:CPU利用率应该为100%,因为两个进程所有指令都是CPU指令。

检查答案是否正确
在这里插入图片描述

    1. 现在用这些参数运行: ./process-run.py -l 4:100,1:0。这些参数指定了一个包含4条指令的进程(都要使用CPU),并且只是简单地发出IO请求并等待它完成。完成这两个进程需要多长时间?(默认每个CPU指令用1个时钟时间,一个IO请求5个时钟时间)用-c检查你的答案是否正确。

      运行结果截图
      在这里插入图片描述
      答案:11个时钟时间,第一个进程花费4个时钟时间,进程结束后,第二个进程发起IO请求花费一个时钟时间,然后处理IO请求花费5个时钟时间,最后IO结束返回花费1个时钟时间。

检查答案
在这里插入图片描述

    1. 现在交换进程的顺序: ./process-run.py -l 1:0,4:100.现在发生了什么?交换顺序是否重要?为什么?同样,用-c看看你的答案是否正确。

      运行截图:
      在这里插入图片描述
      答案:第一个进程先运行,发起IO请求进入阻塞状态,CPU此时会调度第二个进程运行。交换顺序很重要,因为如果先运行的进程进入阻塞之后,可以调度后面的程序占用CPU,CPU的利用率变高,时间效率也会变高。

      检查答案:
      在这里插入图片描述
      对比两个命令的CPU使用率(-p 参数):
      在这里插入图片描述
      在这里插入图片描述
    1. 现在探索另一些参数。一个重要的参数是 -S,它决定了当进程发出I/O请求时系统如何反应。将参数设置为SWITCH_ON_END,表示进程进程I/O操作时,系统不会切换到另一个进程,而是等待进程完成。当你运行以下两个进程时,会发生什么情况?一个执行I/O,另一个执行CPU工作。(-l 1:0,4:100 -c -S SWITCH_ON_END)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1095979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java的共享充电宝管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

AI时代助力程序员与项目经理的双翼飞翔:从开发到成长的秘诀

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

企业网盘中支持在线编辑的有哪些选项?

企业网盘作为现代企业不可或缺的工具之一&#xff0c;为企业提供了便捷的文件存储和共享功能。而其中支持在线编辑的解决方案更是减少了对额外软件的依赖&#xff0c;使团队成员可以直接在浏览器中进行实时协作。 什么是在线编辑&#xff1f; 在线编辑是指用户无需下载文件&a…

3D 生成重建008-zero123让扩散模型了解空间信息zero-shot 单图生3d

3D 生成重建008-zero123让扩散模型了解空间信息zero-shot 单图生3d 文章目录 00 论文工作1 论文方法1.1 条件生成微调1.2 维护3d表示 2 效果 0 0 论文工作 之前分享的工作主要尝试是从一个pre-trained 文生图的diffusion模型中去蒸馏知识&#xff0c;从而去维护一个3d的表示…

数据结构上机实验——栈和队列的实现、栈和队列的应用、进制转换、约瑟夫环问题

文章目录 栈和队列上机实验1.要求2.栈的实现&#xff08;以顺序栈为例&#xff09;3.队列的实现&#xff08;以顺序队列为例&#xff09;4.利用栈实现进制转换5.利用队列解决约瑟夫环问题6.全部源码Stack.hQueue.htest.cpp 栈和队列上机实验 1.要求 1.利用栈的基本操作实现将任…

docker-compose部署elk(8.9.0)并开启ssl认证

docker部署elk并开启ssl认证 docker-compose部署elk部署所需yml文件 —— docker-compose-elk.yml部署配置elasticsearch和kibana并开启ssl配置基础数据认证配置elasticsearch和kibana开启https访问 配置logstash创建springboot项目进行测试kibana创建视图&#xff0c;查询日志…

李宏毅生成式AI课程笔记(持续更新

01 ChatGPT在做的事情 02 预训练&#xff08;Pre-train&#xff09; ChatGPT G-Generative P-Pre-trained T-Transformer GPT3 ----> InstructGPT&#xff08;经过预训练的GPT3&#xff09; 生成式学习的两种策略 我们在使用ChatGPT的时候会注意到&#xff0c;网站上…

2023/10/15

文章目录 1.uniapp之Vue2升Vue3值得注意的几点1.1 页面生命周期的使用1.2 引入资源的方式 2. 浏览器本地存储之Cookie和webStorage3. CSS变量 var()的用法4. CSS之实现线性渐变背景5. 图片无法和文字对齐的正确解决方案6. 使用正则处理接口返回的富文本内的图片7. transition实…

Java练习题-获取数组元素最大值

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;Java练习题 &#x1f4ac;个人格言&#xff1a;不断的翻越一座又…

[cpp primer随笔] 11. 内联函数与constexpr函数

1. 内联函数 调用函数一般比对等价表达式求值要慢。因为调用函数除了对表达式求值外&#xff0c;还包含一系列过程&#xff0c;包括堆栈建立、拷贝实参、跳转执行等等。而在程序之中&#xff0c;通常存在一些优化规模较小、流程直接、却调用频率很高的函数&#xff0c;我们可以…

51系列—基于51单片机的集中抄表设计(代码+文档资料)

概述 自动抄表&#xff08;Automatic Meter Reading-AMR&#xff09;是指采用通讯和计算机网络等技术自动读取和处理表计数据。发展电能自动抄表技术是提高用电管理水平的需要&#xff0c;也是网络和计算机技术迅速发展的必然。在用电管理方面&#xff0c;采用自动抄表技术&am…

YOLOv5-QAT量化部署

目录 前言一、QAT量化浅析二、YOLOv5模型训练1. 项目的克隆和必要的环境依赖1.1 项目克隆1.2 项目代码结构整体介绍1.3 环境安装 2. 数据集和预训练权重的准备2.1 数据集2.2 预训练权重准备 3. 训练模型3.1 修改数据配置文件3.2 修改模型配置文件3.3 训练模型3.4 mAP测试 三、Y…

浅谈“智慧园区”

前言&#xff1a;国庆《中国智慧园区发展白皮书&#xff08;2022&#xff09;》&#xff0c;很全面的介绍智慧园区的起源、发展阶段、涉及内容、未来规划、竞争格局等。做了些笔记&#xff0c;这对在智慧园区工作的伙伴应该很有帮助&#xff0c;下面是笔记和一些公开资料的整合…

小谈设计模式(30)—Java设计模式总结

小谈设计模式&#xff08;30&#xff09;—Java设计模式总结 专栏介绍专栏地址专栏介绍 总括三个主要类别abc 创建型模式&#xff08;Creational Patterns&#xff09;常见的创建型模式单例模式&#xff08;Singleton Pattern&#xff09;工厂模式&#xff08;Factory Pattern&…

【计算机网络笔记】分组交换中的报文交付时间计算例题

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 系列文章目录题目解答 题目 在下图所示的采用“存储-转发”方式的分组交换网络中所有链路的数据传输速率为100 Mbps&#xff0c;分…

[开源]基于Vue+ElementUI+G2Plot+Echarts的仪表盘设计器

一、开源项目简介 基于SpringBoot、MyBatisPlus、ElementUI、G2Plot、Echarts等技术栈的仪表盘设计器&#xff0c;具备仪表盘目录管理、仪表盘设计、仪表盘预览能力&#xff0c;支持MySQL、Oracle、PostgreSQL、MSSQL、JSON等数据集接入&#xff0c;对于复杂数据处理还可以使用…

【具身智能模型1】PaLM-E: An Embodied Multimodal Language Model

论文标题&#xff1a;PaLM-E: An Embodied Multimodal Language Model 论文作者&#xff1a;Danny Driess, Fei Xia, Mehdi S. M. Sajjadi, Corey Lynch, Aakanksha Chowdhery, Brian Ichter, Ayzaan Wahid, Jonathan Tompson, Quan Vuong, Tianhe Yu, Wenlong Huang, Yevgen C…

Trello的替代方案有哪些?6种国内外选择!

Trello是一个功能强大的项目管理工具&#xff0c;可以帮助团队组织和跟踪他们的工作。然而它并不是唯一的工具。Trello有很多替代方案&#xff0c;它们提供了独特的功能和不同的方法来管理任务和项目。以下是Trello的一些优秀替代方案&#xff1a;Zoho Projects、Basecamp、Wri…

NET 8发布首个RC,比.NET 7的超级快更快!

NET 8 发布了首个 RC。据称 RC 阶段会发布两个版本&#xff0c;正式版将于 2023 年 11 月 14 日至 16 日在 .NET Conf 2023 上推出。.NET 8 是长期支持 (LTS) 版本&#xff0c;将会获得 3 年技术支持。 公告写道&#xff0c;此版本为 Android 和 WASM 引入了全新的 AOT 模式、…

Leetcode—27.移除元素【简单】

2023每日刷题&#xff08;一&#xff09; Leetcode—27.移除元素 无脑直接法实现代码 int removeElement(int* nums, int numsSize, int val){int i 0;int length 0;int j 0;while(i < numsSize) {// 存在等于val的数组元素if(nums[i] val) {j i;int flag 0;while(j…