操作系统包括一个调度程序,用于控制不同的线程和进程何时进入CPU执行。调度程序可以使多个程序在单个处理器上同时运行。不同的操作系统,实现了各种各样的调度算法,而用户无法控制程序的各个部分何时被执行。
本文简单介绍一下操作系统的调度如何影响多线程执行结果,下面这个Python程序,创建了两个名为Barron和Olivia的线程,连续切割蔬菜大约1秒钟。
#!/usr/bin/env python3
""" Two threads chopping vegetables """
import threading
import time
chopping = True
def vegetable_chopper():
name = threading.current_thread().getName()
vegetable_count = 0
while chopping:
print(name, 'chopping a vegetable!')
vegetable_count += 1
print(name, 'chopped', vegetable_count, 'vegetables.')
if __name__ == '__main__':
threading.Thread(target=vegetable_chopper, name='Barron').start()
threading.Thread(target=vegetable_chopper, name='Olivia').start()
time.sleep(1) # chop vegetables for 1 second
chopping = False # stop both threads from chopping
在vegetable_chopper
函数中,程序使用线程模块的current_thread和getName方法来获取当前线程的名称,然后初始化一个局部变量来计算此线程所用的蔬菜数量。
chopping
初始化变量为True,在每次循环迭代过程中,将打印一条切菜的消息并统计本线程vegetable_count的值,while循环结束后,vegetable_chopper
函数打印总切菜数。
我们创建并启动两个线程来执行vegetable_chopper
函数并传入字符串Barron和Olivia为name参数。 Python允许将线程名称设置为用于标识线程的任何内容。在启动两个线程之后,程序会休眠一秒钟,然后将chopping
变量设置为False,两个线程中停止while循环。
现在来看一下执行结果:
$ python execution_scheduling.py
...
Olivia chopping a vegetable!
Olivia chopping a vegetable!
Olivia chopping a vegetable!
Barron chopping a vegetable!
Olivia chopping a vegetable!
Barron chopping a vegetable!
Barron chopping a vegetable!
Barron chopping a vegetable!
Barron chopping a vegetable!
Olivia chopping a vegetable!
Olivia chopping a vegetable!
Olivia chopping a vegetable!
Barron chopping a vegetable!
Olivia chopping a vegetable!
Barron chopping a vegetable!
Olivia chopped 24329 vegetables.
Barron chopped 23313 vegetables.
最后,这两个线程在大致相同的时间开始和停止,但它们执行了不同的次数,这说明操作系统调度并不总是公平的,如果再次运行该程序,Barron和Olivia的结尾数量又会与上次运行的不一致。这说明多线程程序的设计不应该依赖于操作系统的调度。