Logo

郎哥编程

线程同步与sleep方法

2019-04-29 864

sleep方法是time模块提供的一个中断线程运行一段时间的方法,该方法可以把当前正在运行的线程挂起一段时间(时间值由参数传入,时间单位是秒),挂起时间到期后,Python会在适当的时间再次唤醒该线程。

先看一个例子代码:

import time
 import threading
 class MyThread(threading.Thread):
     def __init__(self,incount):
         threading.Thread.__init__(self)
         self.count = incount
     def run(self):
         r1 = range(0,self.count)
         for i in r1:
             print("计数: %d" % (i))
 def main():
     t1 = MyThread(5)
     #设置线程名称
     t1.setName("计数器线程");
     #输出线程状态
     print("线程状态:%s" % (t1.is_alive()))
     #启动线程
     t1.start();
     # 输出线程状态
     print("线程状态:%s" % (t1.is_alive()))
     #中断主线程5秒
     print("中断开始 : %s" % (time.ctime()))
     time.sleep(5)
     print("中断结束 : %s" % (time.ctime()))
     #输出线程名称
     print("线程名称:%s" % (t1.getName()))
 if __name__ == "__main__":
     main()

在main方法中,主线程启动子线程后,调用time模块的sleep方法将主线程挂起5秒。在主线程挂起过程中,子线程仍然在执行,不受主线程的挂起影响。程序输出结果如下图所示:

 image.png     

图 1 使用sleep挂起主线程

从输出结果可以看出,主线程挂起(中断)后,主线程创建的子线程MyThread仍然在运行,主线程等待5秒后再继续执行。

上面的例子代码让我们了解了sleep的具体用法,那么sleep方法的具体应用场景是什么?实际应用编程中,在什么情况下需要使用sleep方法呢?

考虑一个编程任务。要求模拟一个文档上传服务处理程序,若干用户并发上传不同格式的文档,该服务程序需要启动一个转换线程把用户上传的文档统一转换为PDF文档。转换完成后,需要将该文档存储路径设置到文档对象中,并输出该文档信息。另外,模拟程序不需要处理实际的文档,模拟处理过程即可。

既然是并发转换文档需求,程序需要采用多线程处理。对每个用户的转换请求创建一个线程A,在线程A中,考虑到文档格式转换操作时间较长,需要创建一个转换文档格式的线程B。程序处理框架如下图所示:

image.png

图2 文档上传服务程序处理过程

用户发出上传文档请求,主服务线程接收到请求后,创建一个处理该文档的A线程。A线程启动后,创建一个文档转换线程B,B线程负责文档格式的转换工作。A线程需要等待B线程完成文档转换工作后,存储并输出文档信息。上述过程涉及到A线程和B线程的同步,A线程创建B线程后,需要等待B线程完成工作,才能继续执行。此时,A线程就可以调用sleep方法休眠一段时间,等待B线程完成工作。

(1)首先建立Document类,该类有两个属性,分别是docName、savePath,savePath属性值的设置在B线程进行。代码如下:

# 声明文档类
 class Docment:
      # 文档类构造方法
     def __init__(self, inDocName, inSavePath):
         self.docName = inDocName
         self.savePath = inSavePath
 
     def getDocName(self):
         return self.docName
 
     def getSavePath(self):
         return self.savePath
 
     def setDocName(self, inDocName):
         self.docName = inDocName
 
     def setSavePath(self, inSavePath):
         self.savePath = inSavePath

(2)建立文档转换线程类(B线程),该类通过for循环模拟长时间处理操作,并设置传入doc对象的savePath属性,表示文档转换完成。代码如下:

import threading
 import Document
 class Convert(threading.Thread):
     def __init__(self, inDocument):
         threading.Thread.__init__(self)
         self.doc = inDocument
     def run(self):
         #模拟长时间处理操纵
         r1 = range(0, 1000)
         for i in r1:
             pass
         self.doc.setSavePath(self.doc.getDocName() + "_path")
     def getDocment(self):
         return self.doc

 (3)建立请求处理线程类(A线程),该类启动文档转换线程,并调用sleep方法自身休眠10秒,等待文档转换工作的完成。

import threading
 import Document
 import Convert
 import time
 class Process(threading.Thread):
     def __init__(self, inDocument):
         threading.Thread.__init__(self)
         self.doc = inDocument
     def run(self):
         covert = Convert.Convert(self.doc)
         covert.start()
         time.sleep(3)
         pdoc = covert.getDocment()
         if pdoc.getSavePath() == "":
             pass
         else:
             print("%s 处理完成,存储路径为 %s \n" % (pdoc.getDocName(),pdoc.getSavePath()))
 
     def getDocment(self):
         return self.doc

(4)建立主线程类,该类首先初始化文档列表,然后启动线程对每个文档进行处理。

import Document
 import Process
 #声明文档列表
 document_list = []
 def initDocument():
     r1 = range(0, 5);
     for i in r1:
         doc = Document.Docment("文档" + str(i),"")
         document_list.append(doc)
 def main():
     initDocument()
     for i in range(len(document_list)):
         doc = document_list[i]
         process = Process.Process(doc)
         process.start()
 if __name__ == '__main__':
     main()

程序输出结果如下图所示:

image.png

图 2 文档处理程序输出结果

当线程需要等待资源或者信号到达才能继续执行时,可以采用sleep方法让线程自身休眠等待资源和信号。当线程唤醒时,需要线程自身判断等待的资源是否满足或信号是否到达,当资源仍然不能满足或信号仍未到达时,需要提供一种持续等待的机制,直到资源满足或信号到达。


代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论