首页 新闻 会员 周边

python采集时使用线程,一直无限创建如何固定分配

0
悬赏园豆:20 [已解决问题] 解决于 2020-06-13 21:08

初学python.. 在写某功能时感觉慢,用了线程,由于程序类似死循环,每执行一次就会不停的创建线程,在测试的过程中虽然执行很快,但是内存猛涨,有大佬帮忙看看吗。

=======================================================
import requests
from lxml import etree
import threading

lock=threading.Lock() #创建线程锁
initial = ['gif图片'] #初始集合
existed = [] #已存在的

处理得到的html源码,从中提取关键词,并写入文件

def processHTML(self):
etree_obj = etree.HTML(self)
table_th = etree_obj.xpath('//div[@id="rs"]/table//tr//th//text()')
print('当前词根:'+str(table_th))
if (len(table_th) > 0):
for item in range(len(table_th)):
# 过滤关键词,必须包含某词
if 'gif' in table_th[item]:
# 如果已存在的集合中不存在该关键词则说明它是新的,则继续累加到任务集合中
if table_th[item] not in existed:
initial.append(table_th[item])

                # 一直操作IO,不加锁,错误时文件内容乱码
                with lock:
                    # 将最新采集到的词追加写入文件中
                    with open('keyword.txt', "a", encoding='utf-8') as file:
                        file.write(table_th[item] + "\n")

print('待采集:' + str(len(initial)))
print('已得到:' + str(len(existed)))
if(len(initial)>0):
    with lock:
        runStart()

线程下载源码

def threadDown(self):
userAgen = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Edg/81.0.41'
}
try:

    str = requests.get(self, headers=userAgen, timeout=30)
    # 传递源码,提取关键词
    processHTML(str.text)
except Exception as Err:
    print('异常:' + str(Err))

生成关键词采集url

def create_url(self):
print('当前关键词:'+self)
threadDown('https://www.baidu.com/s?wd='+self+'&pn=0')

def runStart():
i = 0
while i < len(initial):
# print(initial[i])
existed.append(initial[i])

    # create_url(initial[i])  #传递关键词生成采集url
    run = threading.Thread(target=create_url, args=(initial[i],))
    run.start()
    initial.pop(i)

if name == 'main':
runStart()

上面代码运行会一直不停的创建线程,直到内存99%
关于功能,是想让它一直不停的获取关键词,所以每次获取完都会判断inital集合,然后再次启动,理想的方式是自动判断inital集合中有多少需要执行的任务,然后自动分配多少线程去执行并且释放,例如数量超过100,则分配5个线程跑,超过500则分10个或更多,如何写,有点迷,希望有空前辈指点指点

lixia7的主页 lixia7 | 初学一级 | 园豆:6
提问于:2020-05-20 17:17
< >
分享
最佳答案
0

限制创建线程数量用:Semaphore

num=inital集合数量

sem=threading.Semaphore(num/20)

 

import threading
import time
 
sem=threading.Semaphore(4)  #限制线程的最大数量为4个
 
def gothread():
    with  sem:  #锁定线程的最大数量
        for i in range(8):
            print(threading.current_thread().name,i)
            time.sleep(1)
 
for i in range(5):
    threading.Thread(target=gothread).start()

网上很多例子的;

收获园豆:20
悟行 | 专家六级 |园豆:12559 | 2020-05-20 17:42

试了下,停掉 gothread 里的time.sleep 程序直接停止了,这是什么原理,如果加上sleep速度达不到理想状态(虽然稳定,但速度有点慢),还有 with sem: 好像并没有起作用,

另外在不填写time.sleep的情况下,需要在处理函数判断inital集合是否为空,不空则重新唤起runstart,这样会一直创建线程,如果能在子程序processHTML中控制启动的线程数量则完美了

import threading
import time
import requests
from lxml import etree

initial = ['gif图片'] #初始集合
existed = [] #已存在的
sem = threading.Semaphore(15) # 限制线程的最大数量为4个

处理得到的html源码,从中提取关键词,并写入文件

def processHTML(self):

etree_obj = etree.HTML(self)
table_th = etree_obj.xpath('//div[@id="rs"]/table//tr//th//text()')
print('当前词根:'+str(table_th))
for item in range(len(table_th)):
    # 过滤关键词,必须包含某词
    if 'gif' in table_th[item]:
        # 如果已存在的集合中不存在该关键词则说明它是新的,则继续累加到任务集合中
        if table_th[item] not in existed:
            initial.append(table_th[item])
            print('写出词-----------')
print('待采集:' + str(len(initial)))
print('已得到:' + str(len(existed)))
# runStart不加time.sleep时,不加下面判断则会停止,加上则达不到理想状态,如果启用下面判断则会一直创建子线程。。。虽然速度快,但是内存涨的也快。
# if(len(initial)>0):
#     # runStart()

线程下载源码

def threadDown(self):
userAgen = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Edg/81.0.41'
}
try:
str = requests.get(self, headers=userAgen, timeout=30)
# 传递源码,提取关键词
processHTML(str.text)

except Exception as Err:
    print('异常:' + str(Err))

def gothread(self):
# with sem: # 锁定线程的最大数量
threadDown('https://www.baidu.com/s?wd='+self+'&pn=0')

def runStart():
with sem: # 锁定线程的最大数量
i = 0
while i < len(initial):
existed.append(initial[i])
print('当前线程:' + threading.current_thread().name)
threading.Thread(target=gothread,args=(initial[i],)).start()
time.sleep(0.5)
initial.pop(i)
print('当前词数:'+str(len(initial)))
if name == 'main':
runStart()

lixia7 | 园豆:6 (初学一级) | 2020-05-21 11:10
其他回答(1)
0

可以做一个线程池吧,规定线程数量,如果到达最大,则等待

会长 | 园豆:12401 (专家六级) | 2020-05-21 09:06
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册