DefSw0rd 发表于 2023-8-13 09:42:29

请问下为啥我的这个程序占用内存这么大?

多线程260多mb,单线程也有90多mb,都快赶上3a大作了。
诸位gpt说的很有道理,但是:
1.我这些字典就存几个项目,不应该占用这么多空间吧!
2.多线程改成单线程因为是一步一步的运行,速度会很慢
3.我这里检测的网址每30s更新一次html。。。我还是用的crontab定每小时运行,不存在一直吃内存的问题,我只是想把这个瞬时内存降下来

import re
from sys import path
from json import dump, load
from multiprocessing import Process
from time import sleep

from requests import get
from bs4 import BeautifulSoup

from semi import checkandWrite
from logmod import logger
# 搜寻模式,写这种最简单的管道符号正则即可
meth = r"东方财富|医疗|储能|电池"
# 含url的字典,键值是当前探测对象的总命名。
# 每键下对应一个列表。
# 列表0:网站地址;
# 列表1:探测至最新页面(不存在)时的指示标题<title/>;
# 列表2:正文的text对应的soup元素,
url_dict = {
    "office369" : ["这里填url1", "你访问的页面不存在", {'class':'art-content'}],
    "topye" : ["这里填url2", "-上野财新网", {'id':'newscontent'}],
}

def rGet(url):
    # 获取页面内容
    page = get(url, headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
                  AppleWebKit/537.36 (KHTML, like Gecko) \
                  Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48',
                  'Accept':'text/html,application/xhtml+xml,*/*'})
    return page

def search4result(regex, string:str):
    # 用正则表达式忽略大小写搜寻关键词。返回regex的搜索结果对象
    return re.search(regex, string, flags=re.I)

def get_url_soup(url:str):
    # 获取网站的美丽汤值对象
    return BeautifulSoup(rGet(url).content, 'html.parser')

def get_fuckads(name:str, this_url:str, detect_title:str, detect_attr:dict):
    """
    向上寻找到网站最新的更新页面,一个一个的检索关键词。
    attrs:
      name: 当前探测对象的总命名。
      this_url: 网站地址;
      detect_title: 探测至最新页面(不存在)时的指示标题<title/>;
      detect_attr: 正文的text对应的soup元素。
    return:
      None.
    """
    neo_dict = dict()
    with open(f"{path}\\detect\\status_{name}.json", "r+", encoding="utf-8") as f:
      # json存储的字典的简单结构:{"name": "office369", "now": 190904}
      stat = load(f)
      start_counter = stat['now']
      logger.info(f"<<!FUCKADS!>>: {name}: running from {start_counter}...")#日志打印开始信号
      try:
            temp_soup = get_url_soup(f"{this_url}{stat['now']}.html")
            #for循环我糊的,不知道该怎么写。。。
            while(temp_soup.title.text != detect_title): #标题不是不存在的网页标题
                now_title = temp_soup.title.text    #取标题正文
                now_url = f"{this_url}{stat['now']}.html"   #当前网址
                now_text = temp_soup.find("div", attrs=detect_attr).text #正文内容
                #now_text = now_text.text.replace(" ", "").replace("\n", "")
                title_result = search4result(meth, now_title)
                text_result = search4result(meth, now_text)
                # 标题有关键词 or 正文有关键词
                is_exist = bool(title_result) or bool(text_result)
                if(is_exist):
                  #日志记一笔
                  logger.critical(f"<<!FUCKADS!>>:\n{now_title} : {now_url} \
                                    \n{title_result}, {text_result}")
                  neo_dict = now_url   #字典加一笔
                stat['now'] += 1
                temp_soup = get_url_soup(f"{this_url}{stat['now']}.html")
      except Exception: #你看,我as e都不敢用,生怕e占了内存空间
            # 我实在是不晓得那些attrError或者typeError是怎么出来的
            # 明明设定了只要title相等循环就可以结束了!
            pass
      logger.info(f"<<!FUCKADS!>>: {name}:DONE from {start_counter} tu {stat['now']}")
      # 清空json,字典存储与写入json
      f.seek(0, 0)
      f.truncate(0)
      dump(stat, f)
    if neo_dict:    #逐个写入
      for url in neo_dict.values():
            checkandWrite(url, name)

if __name__ =="__main__":
    for name in url_dict.keys():
      #内存占用这么多的话就不怎么敢玩多线程了
      #get_fuckads(name, url_dict, url_dict,url_dict)
      Process(target=get_fuckads,
                args=(name, url_dict, url_dict,url_dict, )).start()
      sleep(1)

isdkz 发表于 2023-8-13 09:42:57

这个程序占用内存较大的原因可能有以下几点:

1. 字典占用空间:虽然你的字典只存储了几个项目,但是字典在内存中的存储方式是通过哈希表来实现的,而哈希表需要占用一定的内存空间来存储键值对。如果你的字典中的键值对较多,那么占用的内存空间也会相应增加。

2. 多线程和单线程的内存占用:多线程会创建多个线程,每个线程都有自己的栈空间和线程上下文等数据结构,这些都会占用一定的内存空间。而单线程只有一个线程,所以内存占用会相对较少。

3. 网页更新频率和内存占用:你的程序每30秒更新一次网页内容,但是你使用crontab定时每小时运行,这意味着程序会在每次运行时重新获取网页内容并存储,这可能导致内存占用逐渐增加。如果你只是想降低瞬时内存占用,可以考虑使用定时任务更频繁地运行程序,或者在每次运行结束后手动释放内存。

另外,你的代码中存在一些问题:
·temp_soup.title.text应该改为temp_soup.title.string ,因为title标签中的内容是通过string属性获取的。
· 在异常处理中,最好使用具体的异常类型来捕获异常,以便更好地处理错误。

希望以上解答对你有帮助!如果还有其他问题,请随时提问。

陶远航 发表于 2023-8-13 09:43:02

根据你提供的代码,我看到有一些可能导致内存占用增加的原因:

1. 每个进程都会加载相同的模块和字典。在多线程中,每个线程都是独立的,它们需要单独加载这些模块和字典,这可能导致内存占用增加。你可以考虑将这些模块和字典加载放在主线程中,然后通过参数传递给子进程。

2. 在循环中,你使用了一个无限循环,不断地访问网页,直到标题等于某个特定值。这会导致程序一直运行,内存占用不会释放。你可以考虑在循环中添加一个退出条件,例如设置一个最大循环次数或者检测到内存占用达到一定阈值时退出循环。

3. 每个进程结束后,你并没有显式地释放资源,例如关闭文件。你可以在每个进程结束后执行一些清理操作,包括关闭文件、释放内存等。

另外,使用多线程在某些情况下可能没有明显的速度优势,特别是在使用GIL(全局解释器锁)的语言中,如Python。如果你的程序是I/O密集型的,可以考虑使用异步编程来提高效率。

希望以上提供的建议对你有帮助!
如果问题已经解决,请设置最佳答案

DefSw0rd 发表于 2023-8-13 10:09:01

isdkz 发表于 2023-8-13 09:42
这个程序占用内存较大的原因可能有以下几点:

1. 字典占用空间:虽然你的字典只存储了几个项目,但是字 ...

第一个URL_DICT(是全局变量,我应该大写的)占用量也就两个键两个列表值(一个列表里面再来两个字符串一个小字典),这个如果要改的话我去找找替代方案。
第二个neo_dict因为数据要求是 “标题:网址”,我想到的是字典的键值对,改起来想不到什么好的替代方案。。。
2和3属于是我自问自答又被答了。。。
title的问题已改

ba21 发表于 2023-8-13 10:09:25

你这不是多线程,是多进程。
使用Thread,不用Process应该会少一些,不过你单线程也有90多mb,可以再查查相关代码,占这点内存关系也不大,程序一关就释放了。

DefSw0rd 发表于 2023-8-13 10:16:36

ba21 发表于 2023-8-13 10:09
你这不是多线程,是多进程。
使用Thread,不用Process应该会少一些,不过你单线程也有90多mb,可以再查查 ...

我这白字先生了属于是{:10_257:}
查的话用调试就可以了吗?

陶远航 发表于 2023-8-13 10:16:52

DefSw0rd 发表于 2023-8-13 10:09
第一个URL_DICT(是全局变量,我应该大写的)占用量也就两个键两个列表值(一个列表里面再来两个字符串一 ...

你这个属于多进程,多线程要用threading中的Thread模块。
比如:
from threading import Thread
t1=Thread(target=print,args=("helloworld",))
t1.start()
这样就可以实现多线程

ba21 发表于 2023-8-13 10:21:59

DefSw0rd 发表于 2023-8-13 10:16
我这白字先生了属于是
查的话用调试就可以了吗?

可以啊,删除 部份代码 运行就知道了。

DefSw0rd 发表于 2023-8-13 10:22:12

陶远航 发表于 2023-8-13 10:16
你这个属于多进程,多线程要用threading中的Thread模块。
比如:



厉害啊,降到一坨线程共占100多m,谢谢了

陶远航 发表于 2023-8-13 10:23:05

DefSw0rd 发表于 2023-8-13 10:22
厉害啊,降到一坨线程共占100多m,谢谢了

嗯嗯,没事
页: [1]
查看完整版本: 请问下为啥我的这个程序占用内存这么大?