纯Python撸一个操作系统

1 引言

最近在了解Python原生的协程机制,通过生成器来实现协程,我最终想要实现几个功能:
第一:单进程、单线程的多任务处理
第二:实现一些基本的系统调用
第三:单进程、单线程实现一个多任务处理功能的web服务器

2 实现多任务

多任务可以通过多进程和多线程的方式很容易实现,但这个不是本篇文章的重点。本文章使用生成器实现多任务。

Task类比较简单,初始化方法指定一个唯一ID,run方法用于激活生成器函数,让生成器函数指定到第一个yield位置返回。
在这里插入图片描述
任务必须要被调度才能够运行,所以第二个类要封装一个调度器-scheduler类,调度器要具备如下基本功能:

  • 存储所有的任务:使用字典存储所有的任务列表
  • 存储就绪的任务:使用队列存储就绪的任务
  • 创建新任务:新建Task对象
  • 结束任务:将Task对象从任务字典中删除
  • 调度任务:将Task对象加入ready队列中
  • 定义一个循环,循环做的事就是不断从任务队列取任务,执行任务
class Task:
    tid = 0

    def __init__(self, target):
        Task.tid += 1
        self.tid = Task.tid  # 定义唯一的id
        self.target = target
        self.send_val = None

    def run(self):
        return self.target.send(self.send_val)

class Scheduler:  # 调度者类
    def __init__(self):
        self.task_storage = {}
        self.ready = queue.Queue()

    def new(self, target):  # 创建新任务
        task = Task(target)
        self.task_storage[task.tid] = task
        self.ready.put(task)
        return task.tid

    def exit(self, tid):  # 退出任务
        del self.task_storage[tid]

    def schedule(self, task):  # 将就绪任务存储到列表中
        self.ready.put(task)

    def main_loop(self):  # 循环队列
        while True:
            task = self.ready.get()
            try:
                result = task.run()
            except StopIteration:
                self.exit(task.tid)
                continue
            self.schedule(task)
            
def sing():
    for i in range(5):
        yield
        print("i am singing...")


def dance():
    for i in range(5):
        yield
        print("i am dancing...")


if __name__ == '__main__':
    s = Scheduler()
    s.new(sing())
    s.new(dance())
    s.main_loop()

"""
i am singing...
i am dancing...
i am singing...
i am dancing...
i am singing...
i am dancing...
i am singing...
i am dancing...
i am singing...
i am dancing...
。。。
"""

main_loop代码是很重要的,这里着重分析一下:
s1:从队列中获取任务
s2:task.run()执行后,cpu就会运行task里面的函数,直到遇到第一个yield,将cpu使用权还给调度器
s3:将任务放回队列的队尾,等待下一次执行

现在我们通过生成器实现了单进程、单线程的多任务

3 系统调用基类

首先定义一个所有系统调用方法的基类,就叫做SystemCall,这个系统调用基类需要定义两个实例属性,分别记录当前task和当前task所在的调度器。
并且定义一个handler实例方法,用于实现系统调用的功能。

class SystemCall: # 所有系统调用类的抽象基类
    def __init__(self):
        self.task = None         # 当前任务
        self.schedule = None     # 当前调度器

    def handler(self):
        raise NotImplementedError

然后重新定义main_loop方法

class Scheduler:
	
    def main_loop(self):  # 循环队列
        while True:
            task = self.ready.get()
            try:
                result = task.run()  # 这里result保存着task函数里yield后面的值
                if isinstance(result, SystemCall): # 如果task是SystemCall类的实例
                    result.task = task # 将当前任务赋给SystemCall实例
                    result.schedule = self # 将当前调度器赋给SystemCall实例
                    result.handler() # 执行相关操作
            except StopIteration:
                self.exit(task.tid)
                continue
            self.schedule(task)

3.1 获取task id

获取任务的进程ID是操作系统中最常用的功能。

class GetID(SystemCall):
    def __init__(self):
        super().__init__()

    def handler(self):
        self.task.send_val = self.task.tid # 将当前任务ID通过生成器对象的send方法给到生成器
        self.schedule.ready.put(self.task) # 然后将task再次排到队列尾部

def sing():
    for i in range(5):
        tid = yield GetID()
        print(f"task id:{tid}, i am singing...")


def dance():
    for i in range(5):
        tid = yield GetID()
        print(f"task id:{tid}, i am dancing...")


if __name__ == '__main__':
    s = Scheduler()
    s.new(sing())
    s.new(dance())
    s.main_loop()

"""
task id:1, i am singing...
task id:2, i am dancing...
task id:1, i am singing...
task id:2, i am dancing...
task id:1, i am singing...
task id:2, i am dancing...
task id:1, i am singing...
task id:2, i am dancing...
task id:1, i am singing...
task id:2, i am dancing...
"""

3.2 创建新任务

类似windows的任务管理器,操作系统都有一个创建新任务的功能。
在这里插入图片描述

class New(SystemCall):
    def __init__(self, target):
        super().__init__()
        self.target = target

    def handler(self):
        tid = self.schedule.new(self.target)  # 通过调度器创建一个新任务
        self.task.send_val = tid  # 将任务的id发送到生成器中
        self.schedule.schedule(self.task)  # 使用调度器调度任务

def foo():
    for i in range(5):
        tid = yield GetID()
        print(f"task id:{tid},i am foo function")

def bar():
    for i in range(5):
        tid = yield GetID()
        print(f"task id:{tid}, i am bar function")
    new_tid = yield New(foo())
    if new_tid:
        print(f"create new task success! tid is {new_tid}")

if __name__ == '__main__':
    s = Scheduler()
    s.new(bar())
    s.main_loop()

"""
task id:1, i am bar function
task id:1, i am bar function
task id:1, i am bar function
task id:1, i am bar function
task id:1, i am bar function
create new task success! tid is 2
task id:2,i am foo function
task id:2,i am foo function
task id:2,i am foo function
task id:2,i am foo function
task id:2,i am foo function
"""

3.3 kill 任务

杀进程是操作系统必备功能之一


class Kill(SystemCall):
    def __init__(self, tid):
        super().__init__()
        self.tid = tid

    def handler(self):
        # 从调度器的任务字典中获取到任务
        task = self.schedule.task_storage.get(self.tid)
        if task: # 如果字典中有这个task
            task.target.close() # 关闭协程,直接抛出StopIteration异常
            self.task.send_val = True # 给生成器一个True
            self.schedule.schedule(self.task) # 再次调度任务

def foo():
    for i in range(5):
        tid = yield GetID()
        print(f"task id:{tid},i am foo function")


def bar():
    for i in range(5):
        tid = yield GetID()
        print(f"task id:{tid}, i am bar function")
    new_tid = yield New(foo())
    if new_tid:
        print(f"create new task success! tid is {new_tid}")
    yield
    result = yield Kill(new_tid)
    if result:
        print(f"kill task success!")


if __name__ == '__main__':
    s = Scheduler()
    s.new(bar())
    s.main_loop()

"""
task id:1, i am bar function
task id:1, i am bar function
task id:1, i am bar function
task id:1, i am bar function
task id:1, i am bar function
create new task success! tid is 2
task id:2,i am foo function
kill task success!
"""

4 协程版web服务器

def handle_client(client, addr):
    print("Connection from", addr)
    while True:
        data = client.recv(65536)
        if not data:
            break
        client.send(data)
    client.close()
    print("Client closed")
    yield  # yield 关键字将一个普通函数变成一个生成器函数


def server(port):
    print("Server starting")
    sock = socket.socket()
    sock.bind(("", port))
    sock.listen(5)
    while True:
        # 阻塞
        client, addr = sock.accept()
        yield New(handle_client(client, addr))


def alive():
    while True:
        print("I'm alive!")
        yield


if __name__ == '__main__':
    s = Scheduler()
    s.new(alive())
    s.new(server(8888))
    s.main_loop()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kobe_OKOK_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值