初学python.. 在写某功能时感觉慢,用了线程,由于程序类似死循环,每执行一次就会不停的创建线程,在测试的过程中虽然执行很快,但是内存猛涨,有大佬帮忙看看吗。
=======================================================
import requests
from lxml import etree
import threading
lock=threading.Lock() #创建线程锁
initial = ['gif图片'] #初始集合
existed = [] #已存在的
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))
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个或更多,如何写,有点迷,希望有空前辈指点指点
限制创建线程数量用: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()
网上很多例子的;
试了下,停掉 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个
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()
可以做一个线程池吧,规定线程数量,如果到达最大,则等待