导航:首页 > 编程语言 > python实现线程池

python实现线程池

发布时间:2023-06-26 02:05:15

python如何实现线程池

#这个类是线程类,用来在主程序中调用生成一个线程。其实线程池就是线程的集合地,
#能够解决有效统一的管理线程,基本就达到了线程池的目的;
#这一段代码是我的爬虫程序中的一部分,希望对你有用。
classSpider(Thread):
def__init__(self,todo_list):
super().__init__()
self.setDaemon(True)
self.todo_list=todo_list
self.stat=IDLE

defis_idle(self):
returnself.stat==IDLE

defrun(self):
whileTrue:
url=self.todo_list.get()

#开始线程工作


#这个函数就是主函数了,
defmain(max_threads):
########这里和上一个函数就是核心代码了。
#创建N个线程,并启动
print('Spawnspiders')
spiders=[Spider(todo_list)foriinrange(max_threads)]
forspdinspiders:
spd.start()


#python主运行代码:
if__name__=='__main__':
main(max_threads)

只能给你这么多解释了,如果想弄懂,还是要去看看基础知识的。

另外可以查一下有没有封装好的三方库。

② Python中的线程池是什么

多线程的做法是,可以同时创建多个线程放入等待执行的序列中。某个线程执行完毕就将它从序列中移除并销毁。不然的话,即时创建,然后就一定要等到它销毁,那这不是多线程,这是单线程.
进程中根据需要,为一些需要慢资源、竟争性资源的任务创建线程,排除等候执行。
线程需要等待分配,如果短时间建立了多个线程,哪个线程先开始执行,由调度程序决定;
...调度>>>执行>>>循环
当线程执行完毕,销毁线程。
比如说,下载图片:我有一个列表,记录了要下载的300张图片的URL。每个图片的来源可能是不同网站(服务器)。那么,主循环里只需要创建300个【下载】线程。每个线程负责一个URL的下载任务。
然后,调序程序开始调度:线程1有数据过来了,分配时间片给线程1处理这段数据...线程n执行完毕,销毁线程n...线程1又有数据过来了,分配时间片给线程1处理这段数据......销毁线程n,没有等待中的线程,调度暂停。
于是,所有的图片下载完了。
这个过程与单线程的不同是,在多线程中,最开始同一时间有300个请求在等待若干个服务器返回数据,而单线程则总是只有一个请求在等待服务器返回数据或者正在处理数据,另外299个请求根本不存在。
这才是多线程与单线程最主要的差别:在等待某个资源的时候,把其它资源给别的线程去使用。

③ 小白都看懂了,Python 中的线程和进程精讲,建议收藏

目录

众所周知,CPU是计算机的核心,它承担了所有的计算任务。而操作系统是计算机的管理者,是一个大管家,它负责任务的调度,资源的分配和管理,统领整个计算机硬件。应用程序是具有某种功能的程序,程序运行与操作系统之上

在很早的时候计算机并没有线程这个概念,但是随着时代的发展,只用进程来处理程序出现很多的不足。如当一个进程堵塞时,整个程序会停止在堵塞处,并且如果频繁的切换进程,会浪费系统资源。所以线程出现了

线程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位。一个进程可以拥有多个线程,而且属于同一个进程的多个线程间会共享该进行的资源

① 200 多本 Python 电子书(和经典的书籍)应该有

② Python标准库资料(最全中文版)

③ 项目源码(四五十个有趣且可靠的练手项目及源码)

④ Python基础入门、爬虫、网络开发、大数据分析方面的视频(适合小白学习)

⑤ Python学习路线图(告别不入流的学习)
私信我01即可获取大量Python学习资源

进程时一个具有一定功能的程序在一个数据集上的一次动态执行过程。进程由程序,数据集合和进程控制块三部分组成。程序用于描述进程要完成的功能,是控制进程执行的指令集;数据集合是程序在执行时需要的数据和工作区;程序控制块(PCB)包含程序的描述信息和控制信息,是进程存在的唯一标志

在Python中,通过两个标准库 thread 和 Threading 提供对线程的支持, threading 对 thread 进行了封装。 threading 模块中提供了 Thread , Lock , RLOCK , Condition 等组件

在Python中线程和进程的使用就是通过 Thread 这个类。这个类在我们的 thread 和 threading 模块中。我们一般通过 threading 导入

默认情况下,只要在解释器中,如果没有报错,则说明线程可用

守护模式:

现在我们程序代码中,有多个线程, 并且在这个几个线程中都会去 操作同一部分内容,那么如何实现这些数据的共享呢?

这时,可以使用 threading库里面的锁对象 Lock 去保护

Lock 对象的acquire方法 是申请锁

每个线程在操作共享数据对象之前,都应该申请获取操作权,也就是调用该共享数据对象对应的锁对象的acquire方法,如果线程A 执行了 acquire() 方法,别的线程B 已经申请到了这个锁, 并且还没有释放,那么 线程A的代码就在此处 等待 线程B 释放锁,不去执行后面的代码。

直到线程B 执行了锁的 release 方法释放了这个锁, 线程A 才可以获取这个锁,就可以执行下面的代码了

如:

到在使用多线程时,如果数据出现和自己预期不符的问题,就可以考虑是否是共享的数据被调用覆盖的问题

使用 threading 库里面的锁对象 Lock 去保护

Python中的多进程是通过multiprocessing包来实现的,和多线程的threading.Thread差不多,它可以利用multiprocessing.Process对象来创建一个进程对象。这个进程对象的方法和线程对象的方法差不多也有start(), run(), join()等方法,其中有一个方法不同Thread线程对象中的守护线程方法是setDeamon,而Process进程对象的守护进程是通过设置daemon属性来完成的

守护模式:

其使用方法和线程的那个 Lock 使用方法类似

Manager的作用是提供多进程共享的全局变量,Manager()方法会返回一个对象,该对象控制着一个服务进程,该进程中保存的对象运行其他进程使用代理进行操作

语法:

线程池的基类是 concurrent.futures 模块中的 Executor , Executor 提供了两个子类,即 ThreadPoolExecutor 和 ProcessPoolExecutor ,其中 ThreadPoolExecutor 用于创建线程池,而 ProcessPoolExecutor 用于创建进程池

如果使用线程池/进程池来管理并发编程,那么只要将相应的 task 函数提交给线程池/进程池,剩下的事情就由线程池/进程池来搞定

Exectuor 提供了如下常用方法:

程序将 task 函数提交(submit)给线程池后,submit 方法会返回一个 Future 对象,Future 类主要用于获取线程任务函数的返回值。由于线程任务会在新线程中以异步方式执行,因此,线程执行的函数相当于一个“将来完成”的任务,所以 Python 使用 Future 来代表

Future 提供了如下方法:

使用线程池来执行线程任务的步骤如下:

最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

也可以低于 CPU 核心数

使用线程池来执行线程任务的步骤如下:

关于进程的开启代码一定要放在 if __name__ == '__main__': 代码之下,不能放到函数中或其他地方

开启进程的技巧

开启进程的数量最好低于最大 CPU 核心数

④ python线程池ThreadPoolExecutor.submit的数据丢失问题

ThreadPoolExecutor 是 Executor 的子类,它使用线程池来异步执行调用。

关于concurrent.futures模块下的ThreadPoolExecutor类
在使用submit的时候,如果参数传进去的是生成器对象,在某些情况下,生成器对象会被消耗掉一部分或者是全部的数据

以上示例中,尝试二部分是正常且保证是没有问题
而尝试一则会在submit的时候被消耗掉一部分的数据
尝试三这里先利用缓弊汪tee,复制出两个副本,并且调用了其中一个转list,另一个丢给submit方法,卜辩这种情况下,数据不会产生丢失

问扰仔题一 :生成器对象为什么会在submit的时候,丢失了部分数据?
问题二 :尝试三这里复制了副本,对其中一个转list,就不会丢失数据,不转list还是会丢失数据,又是什么原理?

不知道有没知情人士可以帮忙解答下,不胜感激、

⑤ Python多线程总结

在实际处理数据时,因系统内存有限,我们不可能一次把所有数据都导出进行操作,所以需要批量导出依次操作。为了加快运行,我们会采用多线程的方法进行数据处理, 以下为我总结的多线程批量处理数据的模板:

主要分为三大部分:


共分4部分对多线程的内容进行总结。

先为大家介绍线程的相关概念:

在飞车程序中,如果没有多线程,我们就不能一边听歌一边玩飞车,听歌与玩 游戏 不能并行;在使用多线程后,我们就可以在玩 游戏 的同时听背景音乐。在这个例子中启动飞车程序就是一个进程,玩 游戏 和听音乐是两个线程。

Python 提供了 threading 模块来实现多线程:

因为新建线程系统需要分配资源、终止线程系统需要回收资源,所以如果可以重用线程,则可以减去新建/终止的开销以提升性能。同时,使用线程池的语法比自己新建线程执行线程更加简洁。

Python 为我们提供了 ThreadPoolExecutor 来实现线程池,此线程池默认子线程守护。它的适应场景为突发性大量请求或需要大量线程完成任务,但实际任务处理时间较短。

其中 max_workers 为线程池中的线程个数,常用的遍历方法有 map 和 submit+as_completed 。根据业务场景的不同,若我们需要输出结果按遍历顺序返回,我们就用 map 方法,若想谁先完成就返回谁,我们就用 submit+as_complete 方法。

我们把一个时间段内只允许一个线程使用的资源称为临界资源,对临界资源的访问,必须互斥的进行。互斥,也称间接制约关系。线程互斥指当一个线程访问某临界资源时,另一个想要访问该临界资源的线程必须等待。当前访问临界资源的线程访问结束,释放该资源之后,另一个线程才能去访问临界资源。锁的功能就是实现线程互斥。

我把线程互斥比作厕所包间上大号的过程,因为包间里只有一个坑,所以只允许一个人进行大号。当第一个人要上厕所时,会将门上上锁,这时如果第二个人也想大号,那就必须等第一个人上完,将锁解开后才能进行,在这期间第二个人就只能在门外等着。这个过程与代码中使用锁的原理如出一辙,这里的坑就是临界资源。 Python 的 threading 模块引入了锁。 threading 模块提供了 Lock 类,它有如下方法加锁和释放锁:

我们会发现这个程序只会打印“第一道锁”,而且程序既没有终止,也没有继续运行。这是因为 Lock 锁在同一线程内第一次加锁之后还没有释放时,就进行了第二次 acquire 请求,导致无法执行 release ,所以锁永远无法释放,这就是死锁。如果我们使用 RLock 就能正常运行,不会发生死锁的状态。

在主线程中定义 Lock 锁,然后上锁,再创建一个子 线程t 运行 main 函数释放锁,结果正常输出,说明主线程上的锁,可由子线程解锁。

如果把上面的锁改为 RLock 则报错。在实际中设计程序时,我们会将每个功能分别封装成一个函数,每个函数中都可能会有临界区域,所以就需要用到 RLock 。

一句话总结就是 Lock 不能套娃, RLock 可以套娃; Lock 可以由其他线程中的锁进行操作, RLock 只能由本线程进行操作。

⑥ python 线程池的使用

最近在做一个爬虫相关的项目,单线程的整站爬虫,耗时真的不是一般的巨大,运行一次也是心累,,,所以,要想实现整站爬虫,多线程是不可避免的,那么python多线程又应该怎样实现呢?这里主要要几个问题(关于python多线程的GIL问题就不再说了,网上太多了)。

一、 既然多线程可以缩短程序运行时间,那么,是不是线程数量越多越好呢?

显然,并不是,每一个线程的从生成到消亡也是需要时间和资源的,太多的线程会占用过多的系统资源(内存开销,cpu开销),而且生成太多的线程时间也是可观的,很可能会得不偿失,这里给出一个最佳线程数量的计算方式:

最佳线程数的获取:

1、通过用户慢慢递增来进行性能压测,观察QPS(即每秒的响应请求数,也即是最大吞吐能力。),响应时间

2、根据公式计算:服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量

3、单用户压测,查看CPU的消耗,然后直接乘以百分比,再进行压测,一般这个值的附近应该就是最佳线程数量。

二、为什么要使用线程池?

对于任务数量不断增加的程序,每有一个任务就生成一个线程,最终会导致线程数量的失控,例如,整站爬虫,假设初始只有一个链接a,那么,这个时候只启动一个线程,运行之后,得到这个链接对应页面上的b,c,d,,,等等新的链接,作为新任务,这个时候,就要为这些新的链接生成新的线程,线程数量暴涨。在之后的运行中,线程数量还会不停的增加,完全无法控制。所以,对于任务数量不端增加的程序,固定线程数量的线程池是必要的。

三、如何使用线程池
过去使用threadpool模块,现在一般使用concurrent.futures模块,这个模块是python3中自带的模块,但是,python2.7以上版本也可以安装使用,具体使用方式如下:

注意到:
concurrent.futures.ThreadPoolExecutor,在提交任务的时候,有两种方式,一种是submit()函数,另一种是map()函数,两者的主要区别在于:

阅读全文

与python实现线程池相关的资料

热点内容
配置路由器默认路由的命令是 浏览:591
加密计算器是什么 浏览:120
服务器怎么执行sql 浏览:974
小孩子命令 浏览:708
贷款申请系统源码 浏览:268
windowsxp文件夹打开后怎么返回 浏览:664
怎么把pdf变成图片 浏览:797
17年程序员事件 浏览:496
iishttp压缩 浏览:31
公司文件加密后拷走能打开吗 浏览:186
headfirstjava中文 浏览:894
腾讯云服务器怎么放在电脑桌面 浏览:8
批量生成图片的app哪个好 浏览:496
小米10电池校准命令 浏览:96
移动商城系统app如何开发 浏览:692
用安卓手机如何发高清短视频 浏览:339
怎样运行java程序运行 浏览:553
海南根服务器镜像云服务器 浏览:536
weka聚类算法 浏览:452
视频服务器修复是什么意思 浏览:498