14.2线程的创建与启动
import threading # 定义一个普通的action函数,该函数准备作为线程执行体 def action(max): for i in range(max): print(threading.current_thread().getName() + " " + str(i)) # 下面是主程序(也就是主线程的执行体) for i in range(100): print(threading.current_thread().getName() + " " + str(i)) if i == 20: # 创建并启动第一个线程 t1 = threading.Thread(target=action, args=(100,)) t1.start() # 创建并启动第二个线程 t2 = threading.Thread(target=action, args=(100,)) t2.start() print('主线程执行完成!') 输出结果: ... Thread-2 83 MainThread 99 Thread-1 81 Thread-2 84 主线程执行完成! Thread-1 82 Thread-2 85 Thread-1 83 ...
当python程序开始运行后,程序至少会创建一个主线程,主线程的线程执行体就是程序中的主程序-没有放在任何函数中的代码。
以上程序共包含三个线程,这三个线程的执行没有先后顺序,它们以并发方式执行:Thread-1执行一段时间,然后Thread-2或MainThread获得cpu执行一段时间,接下来又换其他线程执行,这就是典型的线程并发执行-cpu以快速轮换的方式在多个线程之间切换,从而给用户一种错觉:多个线程似乎同时在执行。
简言之,多线程就是让多个函数能并发执行,让普通用户感觉到多个函数似乎同时在执行。
在默认情况下 , 主线程的名字为 MainThread , 用户 启动的 多 个线程的名 字依次为 Thread-1 、 Thread-2, Thread-3
14.3线程的生命周期
14.4控制线程
import threading def action(max): for i in range(max): print(threading.current_thread().name + "" + str(i)) threading.Thread(target=action, args=(100,), name="新线程").start() for i in range(100): if i == 20: jt = threading.Thread(target=action, args=(100,), name="被join的线程") jt.start() jt.join() print(threading.current_thread().name + "" + str(i)) 输出结果: ... MainThread19 新线程20 新线程21 新线程22 新线程23 被join的线程0 新线程24 被join的线程1 ...
主线程执行到 i==20 时,程序启动“被join的线程”,所以主线程将一直处于阻塞状态,直到“被join的线程”执行完成。
import threading def action(max): for i in range(max): print(threading.current_thread().name + "" + str(i)) t = threading.Thread(target=action,args=(100,),name="后台进程") t.daemon = True # 必须在start()前设置 t.start() for i in range(10): print(threading.current_thread().name + "" + str(i)) 输出结果: 后台进程0 MainThread0 后台进程1 MainThread1 后台进程2 MainThread2 后台进程3 MainThread3 MainThread4 后台进程4 MainThread5 后台进程5 MainThread6 后台进程6 MainThread7 后台进程7 MainThread8 后台进程8 MainThread9 后台进程9
如果所有前台线程死亡,那么后台线程会自动死亡。
import time for i in range(4): print("当前时间:%s" % time.ctime()) time.sleep(1) # 调用sleep()函数让线程暂停1s 输出结果: 当前时间:Thu Oct 10 22:34:24 2019 当前时间:Thu Oct 10 22:34:25 2019 当前时间:Thu Oct 10 22:34:26 2019 当前时间:Thu Oct 10 22:34:27 2019
14.5线程同步
14.6线程通信
14.7线程池
线程池在系统启动时即创建大量空闲的线程,程序只要将一个函数提交给线程池,线程池就会启动一个空闲的线程来执行它,当该函数执行结束后,该线程并不会死亡,而是再返回到线程池中变成空闲状态,等待执行下一个函数。
14.8线程相关类
定时器
from threading import Timer def hello(): print("hello world!") t = Timer(10.0, hello) # 使用Timer控制10s后执行hello函数 t.start()
from threading import Timer import time # 定义总共输出几次的计数器 count = 0 def print_time(): print("当前时间:%s" % time.ctime()) global t, count count += 1 # 如果count小于10,开始下一次调度 if count < 10: t = Timer(1, print_time) t.start() # 指定1秒后执行print_time函数 t = Timer(1, print_time) t.start() 输出结果: 当前时间:Thu Oct 10 23:11:09 2019 当前时间:Thu Oct 10 23:11:10 2019 当前时间:Thu Oct 10 23:11:11 2019 当前时间:Thu Oct 10 23:11:12 2019 当前时间:Thu Oct 10 23:11:13 2019 当前时间:Thu Oct 10 23:11:14 2019 当前时间:Thu Oct 10 23:11:15 2019 当前时间:Thu Oct 10 23:11:16 2019 当前时间:Thu Oct 10 23:11:17 2019 当前时间:Thu Oct 10 23:11:18 2019
上面程序开始运行后,程序控制 l s 后执行 print_time()函数 。 print_time()函数中的粗体字代码
判断 : 如果 count 小于 10 ,程序再次使用 Timer 调度 ls 后执行 print_time()函数,这样就可以控制
print_time()函数多次重复执行
任务调度
import sched, time import threading # 定义线程调度器 s = sched.scheduler() # 定义被调度的函数 def print_time(name='default'): print("%s 的时间: %s" % (name, time.ctime())) print('主线程:', time.ctime()) # 指定10秒之后执行print_time函数 s.enter(10, 1, print_time) # 指定5秒之后执行print_time函数,优先级为2 s.enter(5, 2, print_time, argument=('位置参数',)) # 指定5秒之后执行print_time函数,优先级为1 s.enter(5, 1, print_time, kwargs={'name': '关键字参数'}) # 执行调度的任务 s.run() print('主线程:', time.ctime()) 输出结果: 主线程: Thu Oct 10 23:18:27 2019 关键字参数 的时间: Thu Oct 10 23:18:32 2019 位置参数 的时间: Thu Oct 10 23:18:32 2019 default 的时间: Thu Oct 10 23:18:37 2019 主线程: Thu Oct 10 23:18:37 2019