Python 中的循环效率

Looping Efficiency in Python

我正在寻找一种更快地执行循环的方法。使用当前代码,计算将永远进行。所以我正在寻找一种使我的代码更高效的方法。

编辑:我不认为任何解释,我需要创建一个程序来完成 8 位数字的所有可能组合,不要忘记包括大写字母、小写字母和数字..然后加密这些可能的 md5组合并将它们保存到文件中。 但是我有新的疑问,这个过程会耗费63年吗?会权衡这个文件吗?,作为脚本的结尾?最近买了一台vps服务器来完成这个任务,但如果需要63年最好不要尝试哈哈..

我是编码新手,感谢所有帮助

import hashlib
from random import choice

longitud = 8
valores = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

def enc(string):
    m = hashlib.md5()
    m.update(string.encode('utf-8'))
    return m.hexdigest()

def code():
    p = ""
    p = p.join([choice(valores) for i in xrange(longitud)])
    text = p
    return text

i = 1
for i in xrange(2000000000000000000):
    cod = code()
    md = enc(cod)
    print cod
    print md
    i += 1
    print i
    f=open('datos.txt','a')
    f.write("%s " % cod)
    f.write("%s" % md)
    f.write('\n')
    f.close()

虽然它有助于调试,但我发现打印会使程序变慢 运行,所以可能不会打印太多。另外,我会将 "f=open('datos.txt', 'a') out from the loop as I can imagine Opening the same file over and over again might cause some time issues, and then move the "f.close()" 移出循环,也移至程序末尾。

已更改

注意你应该使用

for cod in itertools.product(valores, longitud):

而不是通过 random.sample 选择字符串,因为这只会访问给定的字符串一次。

另请注意,对于您给定的值,此循环有 218340105584896 次迭代。输出文件将占用 9170284434565632 字节或 8PB。

首先分析你的程序(使用 cProfile 模块:https://docs.python.org/2/library/profile.html and http://ymichael.com/2014/03/08/profiling-python-with-cprofile.html),但我敢打赌你的程序是 IO 绑定的(如果你的 CPU 使用量永远不会达到100% on one core,这意味着你的硬盘速度太慢,跟不上程序其余部分的执行速度。

考虑到这一点,首先更改您的程序,以便:

  • 它在循环外部打开和关闭文件(打开和关闭文件超级慢)。
  • 它在每次迭代中只进行一次 write 调用(每次都转换为系统调用,这是昂贵的),如下所示:f.write("%s %s\n" % (cod, md))

您没有充分利用具有多个中央处理器的现代计算机的全部功能!这是迄今为止您可以在这里获得的最佳优化,因为这是 CPU 绑定 。注意:对于I/O绑定操作multithreading(使用threading模块)是合适的。

让我们看看 python 如何使用 multiprocessing module 轻松做到这一点(阅读评论):

import hashlib
# you're sampling a string so you need sample, not 'choice'
from random import sample
import multiprocessing
# use a thread to synchronize writing to file
import threading

# open up to 4 processes per cpu
processes_per_cpu = 4
processes = processes_per_cpu * multiprocessing.cpu_count()
print "will use %d processes" % processes
longitud = 8
valores = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
# check on smaller ranges to compare before trying your range... :-)
RANGE = 200000
def enc(string):
    m = hashlib.md5()
    m.update(string.encode('utf-8'))
    return m.hexdigest()

# we synchronize the results to be written using a queue shared by processes
q = multiprocessing.Manager().Queue()

# this is the single point where results are written to the file
# the file is opened ONCE (you open it on every iteration, that's bad)
def write_results():
    with open('datos.txt', 'w') as f:
        while True:
            msg = q.get()
            if msg == 'close':
                break;
            else:
                f.write(msg)

# this is the function each process uses to calculate a single result
def calc_one(i):
    s = ''.join(sample(valores, longitud))
    md = enc(s)
    q.put("%s %s\n" % (s, md))

# we start a process pool of workers to spread work and not rely on
# a single cpu
pool = multiprocessing.Pool(processes=processes)

# this is the thread that will write the results coming from
# other processes using the queue, so it's execution target is write_results
t = threading.Thread(target=write_results)
t.start()
# we use 'map_async' to not block ourselves, this is redundant here,
# but it's best practice to use this when you don't HAVE to block ('pool.map')
pool.map_async(calc_one, xrange(RANGE))
# wait for completion
pool.close()
pool.join()
# tell result-writing thread to stop
q.put('close')
t.join()

此代码中可能还有更多优化需要完成,但是对于像您现在这样的任何 cpu 绑定任务的主要优化是使用多处理。

注意:文件写入的一个简单优化是聚合队列中的一些结果并将它们写入到一起(如果您有许多 cpus 超过单个写入线程的速度)

注意 2:由于 OP 正在寻找 combinations/permutations 的东西,应该注意有一个模块可以做到这一点,它被称为itertools.