操作系统可以同时运行多个任务,比如你一边在用浏览器上网,一边在听网易云音乐,一边在用pycharm敲代码,这就是多任务
。
对于操作系统而言,一个任务就是一个
进程
(
Process
),
有些进程内部同时做多件事情,即同时运行多个子任务,我们把这些子任务称为
线程
(
Thread
)。
所以一个进程至少有一个线程。
单个 CPU 可以执行多进程和多线程,即由操作系统在多个进程或者线程之间快速切换,使得每个进程或者线程短暂的交替运行。例如
任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。
看似每个任务都是交替执行的,但是,由于CPU的执行速度太快了,我们感觉就像所有任务都在同时执行一样。
当下
多核CPU已经普及
,
真正的并行执行多任务只能在多核CPU上实现
,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。
多任务的实现有3种方式:
实现多线程
Python 的标准库提供了两个模块:
_thread
和
threading
,
_thread
是低级模块,
threading
是高级模块,对
_
thread
进行了封装。
通常,我们只需要
使用
threading
这个高级模块
。
threading 实现线程操作
添加线程
导入线程模块:
import threading
获取已激活的线程数:
threading.active_count()
查看现在正在运行的线程:
threading.current_thread()
添加线程:
thread = threading.Thread(target=thread_job,)
注意:
接收参数 target 代表这个线程要完成的任务,需自行定义。
一段完成的小代码:
import threading
def t_job():
print('current_thread: %s' % threading.current_thread())
def main():
thread = threading.Thread(target=t_job,)
thread.start()
if __name__ == '__main__':
main()
current_thread: -8, started 15240)>
注意:
在 windows 平台下,线程(进程)的操作一定要放在 if __name__ == '__main__': 语句下执行。
控制线程
线程开始运行:
thread.start()
控制多个线程的执行顺序:
thread.join()
为什么要控制多个线程的执行顺序?
以下面的例子为例介绍:
假设有 t1_job 和 t2_job 两个任务,第一个任务执行时间10s,第二个任务执行时间1s。
创建以下代码:
import time
import threading
def t1_job():
print("T1 start\n")
for i in range(10):
time.sleep(1)
print("T1 finish\n")
def t2_job():
print("t2 start\n")
for i in range(10):
time.sleep(0.1)
print("t2 finish\n")
thread_1 = threading.Thread(target=t1_job, name='t1')
thread_2 = threading.Thread(target=t2_job, name='t2')
thread_1.start()
thread_2.start()
print("all jobs finished\n")
希望得到的输出是:
T1 start
T2 start
T2 finish
T1 finish
all jobs finished
然而实际的输出是:
T1 start
T2 start
T2 finish
all jobs finished
T1 finish
这种杂乱的执行方式是我们不能忍受的,因此要使用 join() 加以控制,推荐将每个线程对应的 join() 依次放在所有 start() 后面。
可将代码修改如下:
import time
import threading
def t1_job():
print("T1 start\n")
for i in range(10):
time.sleep(1)
print("T1 finish\n")
def t2_job():
print("t2 start\n")
for i in range(10):
time.sleep(0.1)
print("t2 finish\n")
thread_1 = threading.Thread(target=t1_job, name='t1')
thread_2 = threading.Thread(target=t2_job, name='t2')
thread_1.join()
thread_2.join()
print("all jobs finished\n")
线程锁 lock 的操作
在多线程中,所有变量都由所有线程共享
,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。
举个栗子:
import time, threading
c = 0
def t_job(n):
global c
c += n
c -= n