线程内存分析

时间:2014-09-15 13:49:55

标签: python multithreading memory-management memory-leaks

所以我希望这不是重复,但是我要么找不到合适的解决方案,要么我不是100%正在寻找的东西。我编写了一个程序来处理大量请求。我创建一个线程

  1. 从多个api中获取响应,例如:share.yandex.ru/gpp.xml?url=MY_URL以及抓取博客
  2. 解析上述示例中所有请求的响应/ json /使用python-goose提取文章
  3. 将解析后的结果返回给主线程并插入数据库。
  4. 它一直进展顺利,直到它需要撤回我以前没有测试过的大量数据。这样做的主要原因是它超过了我在共享Linux服务器(512mb)上启动kill的共享内存限制。这应该足够了,因为它只有几千个请求,尽管我可能是错的。我正在清除主线程中的所有大数据变量/对象,但这似乎也无济于事。

    我在主函数上运行了一个memory_profile,它创建了一个线程类的线程,如下所示:

    class URLThread(Thread):
        def __init__(self,request):
            super(URLThread, self).__init__()
            self.url = request['request']
            self.post_id = request['post_id']
            self.domain_id = request['domain_id']
            self.post_data = request['post_params']
            self.type = request['type']
            self.code = ""
            self.result = ""
            self.final_results = ""
            self.error = ""
            self.encoding = ""
    
        def run(self):
            try:
                self.request = get_page(self.url,self.type)
                self.code = self.request['code']
                self.result = self.request['result']
                self.final_results = response_handler(dict(result=self.result,type=self.type,orig_url=self.url ))
                self.encoding = chardet.detect(self.result)
                self.error = self.request['error']
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                errors.append((exc_type, fname, exc_tb.tb_lineno,e,'NOW()'))
                pass
    
    @profile
    def multi_get(uris,timeout=2.0):
        def alive_count(lst):
            alive = map(lambda x : 1 if x.isAlive() else 0, lst)
            return reduce(lambda a,b : a + b, alive)
        threads = [ URLThread(uri) for uri in uris ]
        for thread in threads:
            thread.start()
        while alive_count(threads) > 0 and timeout > 0.0:
            timeout = timeout - UPDATE_INTERVAL
            sleep(UPDATE_INTERVAL)
        return [ {"request":x.url,
                  "code":str(x.code),
                  "result":x.result,
                  "post_id":str(x.post_id),
                  "domain_id":str(x.domain_id),
                  "final_results":x.final_results,
                  "error":str(x.error),
                  "encoding":str(x.encoding),
                  "type":x.type}
                for x in threads ]
    

    结果在我通过它的第一批请求中看起来像这样(仅供参考,这是一个链接,因为输出文本在这里不可读,我不能粘贴html表或嵌入图像直到我得到还有2分):

    http://tinypic.com/r/28c147d/8

    并且它似乎没有丢弃后续传递中的任何内存(我在一次批处理100个请求/线程)。我的意思是,一旦一批线程完成,它们似乎每次运行另一个时留在内存中,内存添加如下:

    http://tinypic.com/r/nzkeoz/8

    我在这里做了一些非常愚蠢的事吗?

1 个答案:

答案 0 :(得分:0)

当没有对该对象的引用时,Python通常会释放对象占用的内存。您的multi_get函数返回一个列表,其中包含对您创建的每个线程的引用。因此,Python不太可能释放内存。但是我们需要查看调用multi_get的代码正在做什么才能确定。

要开始释放内存,您需要停止从此函数返回对线程的引用。或者如果你想继续这样做,至少在某处del x删除它们。