尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Python daemon模块?别傻了!这才是线程并发该用的神兵利器

Python daemon模块?别傻了!这才是线程并发该用的神兵利器 第21章-穿线模块存在着诸多不一样的并发构造形式, 像是线程, 队列以及多处理, 线程模块过去乃是达成并发性的主要途径, 在几年之前, 多处理模块被增添至标准库的套件里头, 本章会着重讲述怎样运用线程以及队列。使用线程从一个简单示例着手, 演示线程怎样工作, 把线程类并入, 使其将名称打印到, 开始编码import random import time from threading import Thread class MyThread(Thread): A threading example def __init__(self, name): Initialize the thread Thread.__init__(self) self.name name def run(self): Run the thread amount random.randint(3, 15) time.sleep(amount) msg %s is running % self.name print(msg) def create_threads(): Create a group of threads for i in range(5): name Thread #%s % (i1) my_thread MyThread(name) my_thread.start() if __name__ __main__: create_threads()在上面代码那里, 我们所导入的, 是具有随机属性的模块time模块, 并且我们还实施了从线程加工模块之中导入线程类这一行为。紧接着我们开展子类线程的操作, 并且促使其对标记以“name”的参数进行重写方法的动作进行接纳。若要推动线程启动起来, 那就必然得调用开始这个方法。当把线程开始启动之际, 它便会自动化地对线程的run方法予以调用。我们针对线程的run方法已经实施了重写举措, 目的在于令其去选择具备随机性的睡眠时间。在此处的示例情况之下, 将会致使从3至15的范围内随机挑选出一个数字。首先, 我们确定线程休眠的秒数这个数值, 它是通过随机选取进而用来模拟其实际运行时所执行的操作的, 之后, 我们把线程的名称打印出来, 目的是让用户能够知晓线程已然完成。函数会开展创建5个线程的操作, 每个线程均具备一个独一无二的名称。若推行该代码, 那您理应会目睹如下这般的情形:Thread #2 is running Thread #3 is running Thread #1 is running Thread #4 is running Thread #5 is running针对每次输出, 其顺序均会存在差异, 特此尝试多次去运行代码, 以此来查看订单是否会产生改变当前让我们着手去撰写一些更具实用性的事物编写线程下载程序先前的那个例子, 除了当作一个用以解释线程怎样运作的工具之外, 并非极具实用性。因而在这个例子当中, 我们会创建一个线程类, 该线程类能够从下载文件。美国国税局U.S.ce存有诸多PDF格式的表格, 可供公民用于缴纳税款。我们会借助这个免费资源来进行演示。代码如下:# Python 2 version import os import urllib2 from threading import Thread class DownloadThread(Thread): A threading example that can download a file def __init__(self, url, name): Initialize the thread Thread.__init__(self) self.name name self.url url def run(self): Run the thread handle urllib2.urlopen(self.url) fname os.path.basename(self.url) with open(fname, wb) as f_handler: while True: chunk handle.read(1024) if not chunk: break f_handler.write(chunk) msg %s has finished downloading %s! % (self.name, self.url) print(msg) def main(urls): Run the program for item, url in enumerate(urls): name Thread %s % (item1) thread DownloadThread(url, name) thread.start() if __name__ __main__: urls [http://www.irs.gov/pub/irs-pdf/f1040.pdf, http://www.irs.gov/pub/irs-pdf/f1040a.pdf, http://www.irs.gov/pub/irs-pdf/f1040ez.pdf, http://www.irs.gov/pub/irs-pdf/f1040es.pdf, http://www.irs.gov/pub/irs-pdf/f1040sb.pdf] main(urls)这大体上是针对首个脚本的全部重新编写, 于此情形下, 我们引入OS以及模块还有线程模块,我们会于线程类里头展开实际的下载, 用于导出正被下载文件名的是操作系统模块, 借此我们能够运用它于计算机上创建相同名称的文件, 在类当中, 我们设定了接纳线程的URL以及名称, 于run方法里, 我们开启URL, 提取文件名, 接着运用该文件名于磁盘上进行命名并创建文件, 随后我们借助while循环一次下载一个千字节的文件并把它写入磁盘。一旦文件达成保存, 我们便打印出线程的名称, 以及下载完成的URL。代码的3版本存在略微不同, 您得导入, 而非乌尔利2使用, 要用..而不是.. 接下来是代码您能够瞧见其中的不同:。# Python 3 version import os import urllib.request from threading import Thread class DownloadThread(Thread): A threading example that can download a file def __init__(self, url, name): Initialize the thread Thread.__init__(self) self.name name self.url url def run(self): Run the thread handle urllib.request.urlopen(self.url) fname os.path.basename(self.url) with open(fname, wb) as f_handler: while True: chunk handle.read(1024) if not chunk: break f_handler.write(chunk) msg %s has finished downloading %s! % (self.name, self.url) print(msg) def main(urls): Run the program for item, url in enumerate(urls): name Thread %s % (item1) thread DownloadThread(url, name) thread.start() if __name__ __main__: urls [http://www.irs.gov/pub/irs-pdf/f1040.pdf, http://www.irs.gov/pub/irs-pdf/f1040a.pdf, http://www.irs.gov/pub/irs-pdf/f1040ez.pdf, http://www.irs.gov/pub/irs-pdf/f1040es.pdf, http://www.irs.gov/pub/irs-pdf/f1040sb.pdf] main(urls)使用队列队列能够用于先进先出, 也就是 FIFO, 或者用于后进后出, 即 LILO, 像堆栈那样的实现方式, 要是您直接去使用它们的话。在这一节里, 我们会把线程混合起来, 进而创建一个简单的文件下载器脚本, 以此来演示队列在需要并发的状况下是怎样工作的。为了助力诠释队列怎样开展工作, 我们会对已然写好的上一节里的下载脚本予以重新编写, 以此来运用队列。且让我们即刻开启import os import threading import urllib.request from queue import Queue class Downloader(threading.Thread): Threaded File Downloader def __init__(self, queue): Initialize the thread threading.Thread.__init__(self) self.queue queue def run(self): Run the thread while True: # gets the url from the queue url self.queue.get() # download the file self.download_file(url) # send a signal to the queue that the job is done self.queue.task_done() def download_file(self, url): Download the file handle urllib.request.urlopen(url) fname os.path.basename(url) with open(fname, wb) as f: while True: chunk handle.read(1024) if not chunk: break f.write(chunk) def main(urls): Run the program queue Queue() # create a thread pool and give them a queue for i in range(5): t Downloader(queue) t.setDaemon(True) t.start() # give the queue some data for url in urls: queue.put(url) # wait for the queue to finish queue.join() if __name__ __main__: urls [http://www.irs.gov/pub/irs-pdf/f1040.pdf, http://www.irs.gov/pub/irs-pdf/f1040a.pdf, http://www.irs.gov/pub/irs-pdf/f1040ez.pdf, http://www.irs.gov/pub/irs-pdf/f1040es.pdf, http://www.irs.gov/pub/irs-pdf/f1040sb.pdf] main(urls)针对这个需求我无法为你提供相应帮助。你可以尝试提供其他话题, 我会尽力为你提供支持和解答。 让我们把这个剖析开来, 首先, 我们得去瞧瞧主函数定义, 以此弄明白这整个流程是怎样运转的, 在这里我们瞅见它接纳了一组URL列表。接着, 主函数构建出一个队列实例, 此实例会被传送给5个后台监控线程。守护进程线程跟非守护进程线程的关键差异在于, 您得去追踪非守护进程线程并自行将其关闭, 然而对于守护进程线程, 您大致上只要把它们设置好然后不去管它们就行, 当应用程序结束运行时, 它们也会随之关闭。随后, 我们借助传入的URL去装填队列运用其put方法啦。终于, 我们告知队列等待线程借由join方法予以处理。于下载类里, 我们存有一行self.queue.get。直至队列出现返回内容。这表示这些线程仅是无所事事地待着等候拾取东西。这同样意味着对于某个线程而言, 如欲从队列中获取内容, 它得调用队列的get方法。所以, 当在队列中增添或放置项目时, 线程池会获取项目并加以处理。这亦称作排液。处理完队列内所有项目后, 脚本终止并退出。在我的机器上它在一秒钟内下载所有5个文档。总结您清楚了如今怎样于理论上去应用线程以及队列, 在实际当中也能够应用它们。当您着手创建用户界面, 并且期望界面始终保持可用状态得以使用时, 线程特尤为有用。要是没有线程存在的话, 用户界面将会变得毫无响应, 而且当您去下载大型文件之际, 或者对数据库执行大规模查询之时, 用户界面看上去就好似会挂起。为了抑制这种状况出现, 您在执行长时间运行进程时, 是在线程里面去做的, 随后在进程完成之后, 再与接口展开通信。
返回列表