【问题标题】:Python read from file every time or store values in list?Python每次都从文件中读取或将值存储在列表中?
【发布时间】:2015-12-19 05:21:48
【问题描述】:

我目前正在编写一个 python 脚本来通过蛮力生成每个素数。我目前有一个 >5Mb 的文件,其中包含素数,并且当脚本运行时,它会附加它找到的任何新素数,因此文件会不断变大。每次运行脚本时,这个文件都会被读入一个列表,然后循环计算下一个数字是否是素数,任何新的素数也会被附加到这个列表中。

我的问题是,每次运行脚本时将此文件加载到内存中是否更好,或者我应该在 for 循环中读取文件的下一行,根据正在检查的数字进行处理,然后加载下一个行吗?

前者创建了一个保存在内存中的大列表,但速度非常快,第二个会更慢,因为它必须在每次循环迭代时读取文件,但我认为它不会在内存附近使用。

这是我的代码,它采用配置文件作为参数,其中包含开始查找素数的数字和读取/写入素数的文件:

import sys, math, time

def is_prime(num,primes):
    square = math.floor(math.sqrt(num))
    print('using all prime numbers up to %d' % square)
    for p in primes:
        if p <= square:
            print (p, end='\r')
            if (num % p) == 0:
                return False
        else:
            return True
    return True

def main(argv):
    if len(sys.argv) == 2:
        try:
            try:
                f = open(sys.argv[1], 'r+')
            except IOError:
                sys.exit('Error: File %s does not exist in the current directory...\nUsage: generate_primes.py <prime_file>' % sys.argv[1])
            f.close()

            f = open(sys.argv[1], 'r+')
            low = f.readlines()
            f.close()

            num_to_check = int(low[0].strip('\n'))
            file_name = low[1].strip('\n')
            print(num_to_check)
            print(file_name)

            if num_to_check % 2 == 0:
                num_to_check += 1

            f = open(file_name, 'a+')
            f.seek(0)
            primes = f.readlines()

            print('Processing Primes...')
            for key,i in enumerate(primes):
                primes[key] = int(primes[key].strip('\n'))

            if primes[-1] > num_to_check:
                num_to_check = primes[-1]
                print('Last saved prime is bigger than config value.\nDefaulting to largest saved prime... %d' % primes[-1])

            time.sleep(2)

            new_primes = 0

            while True:
                print('Checking: %s ' % str(num_to_check), end='')
                if is_prime(num_to_check,primes):
                    print('Prime')
                    f.write('%s\n' % str(num_to_check))
                    primes.append(num_to_check)
                    new_primes += 1
                else:
                    print('Composite')
                num_to_check += 2

        except KeyboardInterrupt:
            config_name = time.strftime('%Y%m%d-%H%M%S')
            print('Keyboard Interrupt: \n creating config file %s ... ' % config_name)
            c = open(config_name,'w')
            c.write('%d\n%s' % (num_to_check,file_name))
            c.close()
            f.close()
            print('Done\nPrimes Found: %d\nExiting...' % new_primes)
            sys.exit()


if __name__ == '__main__':
    main(sys.argv[1:])

注意:素数文件不能包含单独的 1,否则每个数字都会合成。

我只从文件中读取的一个问题是能够获取存储的最大素数的值(也就是读取文件中的最后一行)。

【问题讨论】:

  • 正如你所说,这些方法有权衡。对它们进行基准测试,看看哪些更适合您的使用。 (但是,5MB 并不是很多。)
  • primes = f.readlines(); for key,i in enumerate(primes): primes[key] = int(primes[key].strip('\n')) - 我认为这不是你想要的。
  • 唯一应该做的就是遍历整个列表,去掉换行符并将它们更改为整数,以便以后处理它们。

标签: python primes


【解决方案1】:

对速度和内存的优化通常会相互矛盾。有些程序会使用大量内存,但速度非常快(Chrome 正在为此努力),其他程序可能会针对相反的情况,许多程序试图在两者之间寻求平衡。选择重点应该主要围绕问题、用例以及数据(如果您真的很全面的话)。

如果要一遍又一遍地运行脚本,延迟和缓慢的速度确实会很快加起来......您可能需要专注于优化速度。如果脚本运行时间超过一秒左右,并且用户必须无用地盯着屏幕,直到它完成才能继续......您可能需要专注于速度。如果您的操作对时间敏感,那么事情可能需要实时发生,并且您不想因过多的延迟而落后……您可能需要专注于速度。

如果脚本只是偶尔运行,并且主要在时间不敏感的环境中运行,最好是在后台某处,尤其是在有限或低端硬件上...您可能需要关注内存。

更具体地解决您的问题,我可以说我完全同意 Kristjan 的评论,5MB 并不多。现在看着我笔记本电脑上的任务管理器,我可以说我从维基百科打开了两个标签,很长时间没有碰过它们,他们使用的是 33 倍,Facebook 上的一个标签,类似的故事但 280 倍, rubyMine (IDE) 使用的是 244 倍,活动监视器(任务管理器)本身使用的是 33 倍,在 20MB 标记下并没有发生太多事情,除了应该真正组合在一起以减少混乱的小系统内容,以及一些我认为我认为的程序一周前关闭。如果您的应用程序的其余部分保持相对较低的内存占用,您的目标不是弱硬件或嵌入式硬件,那么人们很可能会抱怨速度慢而不是 RAM 中的约 5MB 占用,特别是如果您在清理时清理它完成(更适用于较低级别的语言,但也许del 可以在这里提供帮助)。

实际上,只有您知道您正在处理的问题的限制。好吧,这可能不是真的,但我当然不认识他们。您将不得不就在您的实施中对您来说重要的事情做出决定,这可能会涉及到某个地方的妥协。对两种实现进行基准测试以量化速度增加可能会帮助您证明一个决定优于另一个决定,并且在平局中,当然也可以考虑实施的简易性。

【讨论】:

  • 感谢您的详细回复。是的,我知道 5Mb 不是很多,但是当我让这个脚本运行一个月或更长时间时,我可以预见这个文件会变得非常大。
  • 这是有道理的。就像我说的那样,只有您知道真正发生了什么,并且可以决定您的优先事项应该放在哪里。此外,如果脚本打算运行一个月左右的时间,当你完成它以对抗增长时,可能会释放一些内存,但这取决于你的项目并且可能超出这个问题的范围。祝你好运。
  • 自从我昨晚提出这个问题以来,脚本一直在运行,文件大小已经增长到 ~30Mb,进程占用了 97Mb 的内存。我想我会重写脚本以每次读取文件而不是将其加载到列表中。
猜你喜欢
  • 2018-05-22
  • 2018-02-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-29
  • 1970-01-01
  • 2023-01-19
  • 2016-02-23
  • 2013-12-01
相关资源
最近更新 更多