一、耗时操作
1.耗时操作放到主线程中的问题:
耗时操作放到主线程中,会阻塞线程
多个耗时操作都放到一个线程中执行,最终执行的时间是两个耗时操作的时间和
def long_time(): print('耗时操作开始') time.sleep(10) print('耗时操作结束')def download(file): print('开始下载',file) time.sleep(10) print(file, '下载结束')if __name__ == '__main__': print('====') print(time.time()) download('狄仁杰') download('爱情公寓') print(time.time()) print('!!!') output ====1533731076.2788534开始下载 狄仁杰 狄仁杰 下载结束 开始下载 爱情公寓 爱情公寓 下载结束1533731096.279997!!!
2.怎么解决问题?
使用多线程(创建多个线程)
二、多线程技术1
python内置的threading模块,可以支持多线程
所有的进程默认都有一个线程(一般叫这个线程为主线程),其他的线程叫子线程
如果想要在进程中添加其他的线程,就创建线程对象
import threadingimport timedef download(file, time1): print('开始下载',file) time.sleep(time1) print(file, '下载结束')1.创建线程对象 target: 需要在子线程中执行的函数 args: 调用函数的实参列表(参数类型是列表) 返回值: 线程对象 t1 = threading.Thread(target=download, args=['爱情公寓', 10]) t2 = threading.Thread(target=download, args=['狄仁杰', 5])2.在子线程中执行任务 t1.start() t2.start() print('=====') output 开始下载 爱情公寓 开始下载=====>>> 狄仁杰 狄仁杰 下载结束 爱情公寓 下载结束
三、多线程技术2
写一个自己的线程类
1.写一个类,继承自Thread类
2.重写run方法,在里面规定需要在子线程中执行的任务
3.实现在子线程中执行的任务对应的功能,如果需要参数,通过类的对象属性来传值
from threading import Threadimport requestsimport re# 下载数据class DownloadThread(Thread): """下载类""" def __init__(self, file_path): super().__init__() self.file_path = file_path def run(self): """run方法""" """ 1.写在这个方法的内容就是在子线程中执行的内容 2.这个方法不要直接调用 """ print('开始下载') response = requests.request('GET', self.file_path) data = response.content # 获取文件后缀 suffix = re.search(r'\.\w+$', self.file_path).group() with open('./abc'+suffix, 'wb') as f: f.write(data) print('下载完成...')if __name__ == '__main__': print('=====') t1 = DownloadThread('http://10.7.181.117/shareX/Git.exe') # 通过start间接调用run方法,run方法中的任务在子线程中执行 t1.start() # 直接调用run方法,run方法中的任务在当前线程中执行 # t1.run() t2 = DownloadThread('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533720058151&di=766b5c97653351e805c85881ecaa57d0&imgtype=0&src=http%3A%2F%2Fx.itunes123.com%2Fuploadfiles%2Fb2ab55461e6dc7a82895c7425fc89017.jpg') t2.start() print('!!!!!') 创建一个可供多人向服务器发送信息的功能 服务器端import socketfrom threading import Threadclass ConversationThread(Thread): """在子线程中处理不同的客户端会话""" """ python 中可以在函数参数的后面加一个冒号,来对参数的类型进行说明 """ def __init__(self, conversation:socket.socket, address): super().__init__() self.conversation = conversation self.address = address def run(self): while True: message = input('>>>') self.conversation.send(message.encode()) print(self.address, self.conversation.recv(1024).decode(encoding='utf-8'))if __name__ == '__main__': server = socket.socket() server.bind(('10.7.181.109', 8080)) server.listen(512) while True: conversation, addrrss = server.accept() t = ConversationThread(conversation, addrrss) t.start()
客户端
import socketif __name__ == '__main__': client = socket.socket() client.connect(('10.7.181.109', 8080)) while True: print(client.recv(1024).decode(encoding='utf-8')) message = input('>>>') client.send(message.encode()) 四、join函数 如果一个任务想要在另外一个子线程中的任务执行完成后再执行,就在当前任务前用子线程对象调用join方法,所以join也会阻塞线程,阻塞到对应的子线程中任务执行完为止。from threading import Thread,currentThreadimport timefrom random import randintclass Download(Thread): def __init__(self, file): # 这儿父类的init方法必须调用,否则当前这个创建的对象中就没有新的线程 super().__init__() self.file = file def run(self): print(currentThread()) print('开始下载:%s' % self.file) time.sleep(randint(5, 10)) print('%s下载结束' % self.file)if __name__ == '__main__': # time.time(): 获取当前时间-时间戳 start_time = time.time() t1 = Download('最强Z.mp4') t1.start() t2 = Download('最强A.mp4') t2.start() print('====') # 获取当前线程 """ 主线程: MainThread 子线程: Thread-数字(数字从1开始。) """ print(currentThread()) # 如果一个任务想要在另外一个子线程中的任务执行完成后再执行,就在当前任务前用子线程对象调用join方法 # 所以join也会阻塞线程,阻塞到对应的子线程中任务执行完为止 t1.join() # t2.join() end_time = time.time() print('总共消耗时间:%.2f' % (end_time - start_time))
作者:乍见之欢_715b
链接:https://www.jianshu.com/p/98811fe299a9