
正文
python线程池类函数 python线程池异步处理
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
python 多线程爬取网站数据利用线程池
"""
@author: wangxingchun
多线程(线程池)
下载数据
"""
import requests
import csv
from concurrent.futures import ThreadPoolExecutor as tp
#创建一个csv文件python线程池类函数,注意创建writer对象"csv.writer()"
f = open('xinfadi.csv','w',encoding='utf8')
csvwrite = csv.writer(f)
#如果写入txt文件,不需要创建writer对象。
# f = open('xinfadidata.txt','w',encoding='utf8')
#创建一个函数,以页码做为参数
def down(n_page):
url = ''
data = {'count': 428225,'current': n_page,'limit': 20}
resp = requests.post(url,data=data)
datas =resp.json()
#通过分析数据嵌套情况,获取数据。此处可在网页开发工具json数据中查看分析。
for i in range(len(datas['list'])):
name = datas['list'][i]['prodName']
highPrice = datas['list'][i]['highPrice']
lowPrice = datas['list'][i]['lowPrice']
pubDate = datas['list'][i]['pubDate']
place = datas['list'][i]['place']
csvwrite.writerow((name,highPrice,lowPrice,pubDate,place))#writerow要求写入python线程池类函数的是可迭代对象
# f.writelines(f'{name},{highPrice},{lowPrice},{pubDate},{place} ')
resp.close()
if __name__ == '__main__':
with tp(50) as t: #创建线程池,
for n in range(1,101): #遍历数据网页
t.submit(down,n) #提交给线程池,进行多线程下载
print(f'共{n}页数据下载完毕!')
f.close()
相关问答
Q1: 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 只能由本线程进行操作。
Q2: 提高pycharm线程数
多线程是指在一个进程中,允许几段代码并发式的同时运行。Python 的多线程运算就是利用了这一点,可以让代码的运行方法更加丰富有效。这里需要用到的一个库叫 Threading,这个库可以直接调用其中的函数,或者通过继承类来实现,下面我们来分别通过这两个方法来对运算进行提速。函数多线程
import threading
def func(times, name, ret):
for i in range(times):
print(name + ' run: ' + str(i))
ret[name] = name + " finished with " + str(times) + " times printed"
return
if __name__ == '__main__':
thread_pool = []
ret = {}
th_1 = threading.Thread(target=func, args=[3, 'th_1', ret], name='th_1')
th_2 = threading.Thread(target=func, args=[5, 'th_2', ret], name='th_2')
thread_pool.append(th_1)
thread_pool.append(th_2)
for th in thread_pool:
th.start()
for th in thread_pool:
th.join()
print(ret)
这里我们首先定义了一个函数,func,并且运用 threading 库来做多线程式的函数调用。随后在主程序 main() 内部,我们引入了几个多线程运算的核心概念:线程池 Thread Pool: 线程池是管理多线程的一个容器,帮助分配资源,完成线程的生命周期。你可以自己创建一个容器来管理,或者调用其他容器来管理。这里的线程池是一个列表 List(), 给予变量 thread_pool。
线程类 Thread Class: threading.Thread 是一个线程库里的线程类,帮助你管理,运行目标函数。这里的第一个参数 target= 是目标函数,如果你阅读了 多多教Python:Python 基本功: 7. 介绍函数,就会了解函数也可以当做参数被传递;第二个参数是目标函数的参数,这里是一个列表;第三个参数是线程类的名字,在你自己定义了之后可以在之后管理线程类的时候用到。
开始 Start: 在创建了线程类之后,你需要通过 start() 函数来开始运行你的目标函数。这里通过对线程池列表的循环来一一启动其目标函数。
非阻塞 Non-Blocking: 线程类的 start() 函数是一个非阻塞函数,意思是当目标函数启动了之后,程序就返回了,而不是等到目标函数结束再返回。所以这里可以实现对线程池的线程同时启动,而不是等待前一个结束再开始下一个。
加入 Join: 第二次循环线程池列表的时候,调用了线程类的 join() 函数。join() 函数会等待目标函数运行结束之后返回,是一个阻塞 (Blocking) 函数。目前教程介绍的都是阻塞型函数,在之后的教程中讲到 异步(Asynchronous)的时候会了解如何写非阻塞函数。
返回值 Return:如果你想在多线程运算中获得返回值,有不同的办法,这里介绍其中一种:利用传入的参数来保存返回值。这里在参数列表里传入了一个字典,每一个目标函数把自己的返回值写入这个字典。在 join() 返回之后,就可以查看字典里的返回数值。
Q3: python 线程池的使用
最近在做一个爬虫相关的项目python线程池类函数,单线程的整站爬虫python线程池类函数,耗时真的不是一般的巨大,运行一次也是心累,,,所以,要想实现整站爬虫,多线程是不可避免的,那么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()函数,两者的主要区别在于:
Q4: python多线程并行计算通过向线程池ThreadPoolExecutor提交任务的实现方法
Python的线程池可以有效地控制系统中并发线程的数量。
当程序中需要创建许多生存期较短的线程执行运算任务时,首先考虑使用线程池。线程池任务启动时会创建出最大线程数参数 max_workers 指定数量的空闲线程,程序只要将执行函数提交给线程池,线程池就会启动一个空闲的线程来执行它。当该函数执行结束后,该线程并不会死亡,而是再次返回到线程池中变成空闲状态,等待执行下一个函数。配合使用 with 关键字实现任务队列完成后自动关闭线程池释放资源。
Q5: python如何实现线程池
#这个类是线程类,用来在主程序中调用生成一个线程。其实线程池就是线程的集合地,
#能够解决有效统一的管理线程,基本就达到了线程池的目的;
#这一段代码是我的爬虫程序中的一部分,希望对你有用。
class Spider(Thread):
def __init__(self, todo_list):
super().__init__()
self.setDaemon(True)
self.todo_list = todo_list
self.stat = IDLE
def is_idle(self):
return self.stat == IDLE
def run(self):
while True:
url = self.todo_list.get()
# 开始线程工作
#这个函数就是主函数了,
def main(max_threads):
########这里和上一个函数就是核心代码了。
# 创建 N 个线程,并启动
print('Spawn spiders')
spiders = [Spider(todo_list) for i in range(max_threads)]
for spd in spiders:
spd.start()
#python主运行代码:
if __name__ == '__main__':
main(max_threads)
只能给你这么多解释了,如果想弄懂,还是要去看看基础知识的。
另外可以查一下有没有封装好的三方库。
python线程池类函数的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于python线程池异步处理、python线程池类函数的信息别忘了在本站进行查找喔。







