1.什么是python多线程
Python的多线程指的是在一个Python程序中同时运行多个线程,以达到并发执行多个任务的目的。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
在Python中,多线程的实现通常依赖于内置的threading
模块,这个模块允许用户创建和管理线程。使用多线程可以使得程序能够在等待某些事件(如输入/输出操作)完成时,继续执行其他任务,从而提高程序的整体效率和响应速度。
Python多线程的特点:
-
全局解释器锁(GIL) :Python的标准实现(CPython)中有一个称为全局解释器锁(GIL)的机制,它确保任何时候只有一个线程执行Python字节码。这意味着即便是在多核处理器上,使用多线程也不会带来线程真正并行执行的性能提升。因此,Python的多线程主要适用于处理I/O密集型任务,而不是计算密集型任务。
-
并发而非并行:由于GIL的存在,Python的多线程更多的是实现并发执行,而不是真正的并行执行。并发意味着任务在宏观上同时进行,但在任一时刻,实际上只有一个任务在单个CPU核心上运行。
-
适用场景 :Python多线程非常适合I/O密集型任务,比如网络交互、文件读写等,因为在这些操作中,线程的大部分时间都在等待外部事件完成,而CPU计算需求不高。
2.单线程
下面的示例代码展示了单线程执行的线性特性,即程序中的任务按照它们被调用的顺序依次执行。每个任务都必须等待前一个任务完成后才能开始执行。这种方式在处理涉及等待或延时的任务时可能不够高效,因为它不能同时进行多个任务。
代码示例:
from time import ctime,sleep # 从time模块导入ctime和sleep函数,ctime用于获取当前时间并以易读的字符串形式返回,sleep用于使程序暂停执行指定的秒数
print('当前时间是:%s'%ctime()) # 打印当前的时间,%s是格式化字符串,用于在字符串中插入变量,这里插入的是ctime()函数返回的当前时间字符串
# 单线程
from time import ctime,sleep
# 定义两个函数 music和movie用于模拟听音乐和看电影的活动
def music(what):
# 在每个函数内部有一个for循环,循环两次,每次循环打印当前正在进行的活动及当前的时间,然后通过sleep(1)暂停1秒,模拟正在进行活动的时间消耗
for i in range(2):
print("我正在听音乐:%s,当前时间是:%s"%(what,ctime()))
sleep(1)
def movie(what):
for i in range(2):
print("我正在看电影:%s,当前时间为:%s"%(what,ctime()))
sleep(1)
music('你曾是少年')
movie('泰坦尼克号')
print('今天结束,当前时间为:%s'%ctime())
运行结果:
3.多线程
下面的示例代码展示了如何使用Python的threading模块来创建和运行多线程程序,通过这种方式,可以同时执行多个任务。但是需要注意的是,由于设置了守护线程 (Daemon
Threads),所以两个活动在主线程结束后也终止了,实际并没有按照设定的运行时间完成。守护线程表示当一个线程被设置为守护线程后,它就代表不重要的或在后台运行的服务。最重要的是,当所有非守护线程(即主线程)结束时,守护线程会被强制终止。
# 多线程
from time import ctime,sleep
import threading
def music(what):
for i in range(2):
print("我正在听音乐:%s,当前时间是:%s"%(what,ctime()))
sleep(2)
def movie(what):
for i in range(2):
print("我正在看电影:%s,当前时间为:%s"%(what,ctime()))
sleep(5)
# 开启线程
# 创建一个空列表 threads,用于存储所有线程
# 创建两个线程对象 th1 和 th2,分别指定目标函数music和movie,以及传递给这些函数的参数
# 将创建的线程对象添加到threads列表中
threads=[]
th1=threading.Thread(target=music,args=('你曾是少年',))
threads.append(th1)
th2=threading.Thread(target=movie,args=('泰坦尼克号',))
threads.append(th2)
# 执行线程
for th in threads: # 循环遍历threads列表,启动每个线程
th.daemon=True # 使用setDaemon(True)将线程设置为守护线程。守护线程是一种在后台运行的线程,它的运行不会阻止主程序退出。当主程序退出时,守护线程会被自动终止。
th.start() # 使用start()方法启动线程
print('*****:听音乐和看电影结束{}'.format(ctime()))
# 在多线程环境中,线程的执行顺序和完成时间是不确定的,依赖于操作系统的线程调度
# 在.py执行后,从执行结果来看,子线程(muisc 、move )和主线程(print('*****:听音乐和看电影结束{}'.format(ctime())))都是同一时间启动,但由于主线程执行完结束,所以导致子线程也终止
运行结果:
可以通过阻塞主线程的方式 th.join()
来实现确保音乐和电影的活动能够完全完成。
# 多线程
from time import ctime,sleep
import threading
def music(what):
for i in range(2):
print("我正在听音乐:%s,当前时间是:%s"%(what,ctime()))
sleep(2)
def movie(what):
for i in range(2):
print("我正在看电影:%s,当前时间为:%s"%(what,ctime()))
sleep(5)
# 开启线程
threads=[]
th1=threading.Thread(target=music,args=('丑八怪',))
threads.append(th1)
th2=threading.Thread(target=movie,args=('摔跤吧爸爸',))
threads.append(th2)
# 执行线程
for th in threads:
th.daemon=True
th.start()
th.join() # 阻塞主线程
print('*****:听音乐和看电影结束{}'.format(ctime()))
运行结果:
4.单&多线程对比
import threading # 导入threading包
from time import sleep
import time
def task1():
print ("Task 1 executed." )
sleep(3)
def task2():
print ("Task 2 executed." )
sleep(5)
print("多线程:")
starttime=time.time(); # 记录开始时间
threads = [] # 创建一个线程列表,用于存放需要执行的子线程
t1 = threading.Thread(target=task1) # 创建第一个子线程,子线程的任务是调用task1函数,注意函数名后不能有()
threads.append(t1) # 将这个子线程添加到线程列表中
t2 = threading.Thread(target=task2) # 创建第二个子线程
threads.append(t2) # 将这个子线程添加到线程列表中
for t in threads: # 遍历线程列表
t.daemon=True # 将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起
t.start() #启动子线程
for t in threads: # 再次遍历线程列表
t.join() # 等待每个线程完成
endtime=time.time() # 记录程序结束时间
totaltime=endtime-starttime # 计算程序执行耗时
print ("耗时:{0:.5f}秒" .format(totaltime)) # 格式输出耗时
print('---------------------------')
# 以下为普通的单线程执行过程
print("单线程:")
starttime=time.time()
task1()
task2()
endtime=time.time()
totaltime=endtime-starttime
print ("耗时:{0:.5f}秒" .format(totaltime))
print('主线程')
运行结果:
5.创建和管理定时任务
示例代码演示了如何在 Python 中使用 threading.Timer
类来创建和管理定时任务。threading.Timer
是线程模块中的一个功能,用于在指定的时间后执行一个函数,并且可以重复设置以周期性地执行。
import threading
import time
def fun_timer(): # 定义计时器函数
print("hello timer") # 每次调用计时器函数,打印hello timer
global timer
timer=threading.Timer(2.5,fun_timer) # 创建一个新的 threading.Timer 对象。这个定时器被设置为 2.5 秒后再次执行 fun_timer 函数,实现定时任务的周期性执行
timer.start() # 启动定时器
timer=threading.Timer(1,fun_timer) # 初始化一个定时器,设置为1秒后执行fun_timer函数,这是整个周期性执行的起点
timer.start() # 激活定时器
time.sleep(15) # time.sleep(15)会让主线程暂停15秒,期间fun_timer将被周期性地调用
timer.cancel() # 停止定时器
运行结果:
以上内容总结自网络,如有帮助欢迎转发,我们下次再见!