如何创建一个脚本,为我提供六位代码的所有可能组合
How to create a script that gives me every combination possible of a six digit code
我和一个朋友想创建一个脚本,为我们提供六位代码的所有可能排列,由 36 个字母数字字符(0-9 和 a-z)组成,按字母顺序排列,然后能够看到它们在 .txt 文件中。
我希望它尽可能使用所有 CPU 和 RAM,以便完成任务所需的时间更少。
到目前为止,这是代码:
import random
charset = "0123456789abcdefghijklmnopqrstuvwxyz"
links = []
file = open("codes.txt", "a")
for g in range(0, 36**6):
key = ""
base = ""
print(str(g))
for i in range(0, 6):
char = random.choice(charset)
key += char
base += key
file.write(base + "\n")
file.close()
此代码 随机 生成组合并立即将它们写入 .txt 文件,同时打印它已经创建的代码数量,但它不是按字母顺序排列的(必须事后做),时间太长
如何改进代码以获得预期的结果?
第一件事;有更好的方法可以做到这一点,但我想写一些清晰易懂的东西。
伪代码:
base = "";
for(x1=0; x1<charset.length(); x1++)
for(x2=0; x2<charset.length(); x2++)
for(x3=0; x3<charset.length(); x3++)
.
.
.
{ base = charset[x1]+charset[x2]+charset[x3]+.....+charset[x6];
file.write(base + "\n")
}
对于排列,这可以解决问题:
from itertools import permutations
charset = "0123456789abcdefghijklmnopqrstuvwxyz"
links = []
with open("codes.txt", "w") as f:
for permutation in permutations(charset, 6):
f.write(''.join(permutation) + '\n')
仅供参考,它将创建一个 7.8 GB 的文件
对于组合,这可以解决问题:
from itertools import combinations
charset = "0123456789abcdefghijklmnopqrstuvwxyz"
links = []
with open("codes.txt", "w") as f:
for comb in combinations(charset, 6):
f.write(''.join(comb)+ '\n')
仅供参考,它会创建一个 10.8 兆字节的文件
随机可能效率很低。你可以试试:
from itertools import permutations
from pandas import Series
charset = list("0123456789abcdefghijklmnopqrstuvwxyz")
links = []
file = open("codes.txt", "a")
comb = permutations(charset,6)
comb = list(comb)
comb = list(map(lambda x:return ''.join(x),comb))
mySeries = Series(comb)
mySeries = mySeries.sort_values()
base = ""
for k in mySeries:
base += k
file.write(base + "\n")
file.close()
您可以使用默认 itertools
库中的 itertools.permutaions
。您还可以指定组合中的字符数。
from itertools import permutations
charset = "0123456789abcdefghijklmnopqrstuvwxyz"
c = permutations(charset, 6)
with open('code.txt', 'w') as f:
for i in c:
f.write("".join(i) + '\n')
在我的计算机上运行大约 200 毫秒以创建排列列表,然后花费大量时间写入文件
这是一个组合问题,您试图从长度为 36 的字符集中获得长度为 6 的组合。这将产生大小为 36!/(30!*6!) 的输出。您可以参考 itertools 来解决像您这样的组合问题。可以参考itertools中的Combination函数
Documentation。建议不要使用 Python.
执行此类性能密集型计算
我能想到的最快方法是使用 pypy3 和以下代码:
import functools
import time
from string import digits, ascii_lowercase
@functools.lru_cache(maxsize=128)
def main():
cl = []
cs = digits + ascii_lowercase
for letter in cs:
cl.append(letter)
ct = tuple(cl)
with open("codes.txt", "w") as file:
for p1 in ct:
for p2 in ct:
for p3 in ct:
for p4 in ct:
for p5 in ct:
for p6 in ct:
file.write(f"{p1}{p2}{p3}{p4}{p5}{p6}\n")
if __name__ == '__main__':
start = time.time()
main()
print(f"Done!\nTook {time.time() - start} seconds!")
写入速度约为 10-15MB/s。我相信总文件约为 15GB,因此生成需要 990-1500 秒。结果是在具有 1 个 3.4 ghz 服务器内核 CPU 的 unraid 虚拟机上,以及一个旧的 SATA3 SSD。使用 NVME 驱动器和更快的单核 CPU.
可能会获得更好的结果
虽然这个 post 已经有 6 个答案,但我对其中任何一个都不满意,所以我决定贡献一个我自己的解决方案。
首先,请注意许多答案提供字母的 combinations
或 permutations
,但是 post 实际上需要字母表的笛卡尔积本身(重复 N 次, 其中 N=6)。有(此时)两个答案可以做到这一点,但是它们都 write
次数过多,导致性能不佳,并且还在循环的最热部分连接它们的中间结果(也降低了性能).
为了最大限度地优化,我提供了以下代码:
from string import digits, ascii_lowercase
from itertools import chain
ALPHABET = (digits + ascii_lowercase).encode("ascii")
def fast_brute_force():
# Define some constants to make the following sections more readable
base_size = 6
suffix_size = 4
prefix_size = base_size - suffix_size
word_size = base_size + 1
# define two containers
# word_blob - placeholder words, with hyphens in the unpopulated characters (followed by newline)
# sleds - a tuple of repeated bytes, used for substituting a bunch of characters in a batch
word_blob = bytearray(b"-" * base_size + b"\n")
sleds = tuple(bytes([char]) for char in ALPHABET)
# iteratively extend word_blob and sleds, and filling in unpopulated characters using the sleds
# in doing so, we construct a single "blob" that contains concatenated suffixes of the desired
# output with placeholders so we can quickly substitute in the prefix, write, repeat, in batches
for offset in range(prefix_size, base_size)[::-1]:
word_blob *= len(ALPHABET)
word_blob[offset::word_size] = chain.from_iterable(sleds)
sleds = tuple(sled * len(ALPHABET) for sled in sleds)
with open("output.txt", "wb") as f:
# I've expanded out the logic for substituting in the prefixes into explicit nested for loops
# to avoid both redundancy (reassigning the same value) and avoiding overhead associated with
# a recursive implementation
# I assert this below, so any changes in suffix_size will fail loudly
assert prefix_size == 2
for sled1 in sleds:
word_blob[0::word_size] = sled1
for sled2 in sleds:
word_blob[1::word_size] = sled2
# we write to the raw FileIO since we know we don't need buffering or other fancy
# bells and whistles, however in practice it doesn't seem that much faster
f.raw.write(word_blob)
该代码块中发生了很多神奇的事情,但简而言之:
- 我批处理写入,因此我一次写入
36**4
或 1679616
个条目,因此上下文切换较少。
- 我使用字节数组切片/赋值,同时使用新前缀每批更新所有
1679616
个条目。
- 我对字节进行操作,写入原始文件 IO,扩展前缀分配的循环,以及其他小优化以避免 encoding/buffering/function 调用 overhead/other 性能影响。
请注意,除非您有一个 非常 快速的磁盘和较慢的 CPU,否则您不会从较小的优化中看到太多好处,可能只是写入批处理。
在我的系统上,生成和写入 14880348
文件大约需要 45 秒,这是写入我最慢的磁盘。在我的 NVMe 驱动器上,需要 6.868
秒。
我和一个朋友想创建一个脚本,为我们提供六位代码的所有可能排列,由 36 个字母数字字符(0-9 和 a-z)组成,按字母顺序排列,然后能够看到它们在 .txt 文件中。
我希望它尽可能使用所有 CPU 和 RAM,以便完成任务所需的时间更少。
到目前为止,这是代码:
import random
charset = "0123456789abcdefghijklmnopqrstuvwxyz"
links = []
file = open("codes.txt", "a")
for g in range(0, 36**6):
key = ""
base = ""
print(str(g))
for i in range(0, 6):
char = random.choice(charset)
key += char
base += key
file.write(base + "\n")
file.close()
此代码 随机 生成组合并立即将它们写入 .txt 文件,同时打印它已经创建的代码数量,但它不是按字母顺序排列的(必须事后做),时间太长
如何改进代码以获得预期的结果?
第一件事;有更好的方法可以做到这一点,但我想写一些清晰易懂的东西。
伪代码:
base = "";
for(x1=0; x1<charset.length(); x1++)
for(x2=0; x2<charset.length(); x2++)
for(x3=0; x3<charset.length(); x3++)
.
.
.
{ base = charset[x1]+charset[x2]+charset[x3]+.....+charset[x6];
file.write(base + "\n")
}
对于排列,这可以解决问题:
from itertools import permutations
charset = "0123456789abcdefghijklmnopqrstuvwxyz"
links = []
with open("codes.txt", "w") as f:
for permutation in permutations(charset, 6):
f.write(''.join(permutation) + '\n')
仅供参考,它将创建一个 7.8 GB 的文件
对于组合,这可以解决问题:
from itertools import combinations
charset = "0123456789abcdefghijklmnopqrstuvwxyz"
links = []
with open("codes.txt", "w") as f:
for comb in combinations(charset, 6):
f.write(''.join(comb)+ '\n')
仅供参考,它会创建一个 10.8 兆字节的文件
随机可能效率很低。你可以试试:
from itertools import permutations
from pandas import Series
charset = list("0123456789abcdefghijklmnopqrstuvwxyz")
links = []
file = open("codes.txt", "a")
comb = permutations(charset,6)
comb = list(comb)
comb = list(map(lambda x:return ''.join(x),comb))
mySeries = Series(comb)
mySeries = mySeries.sort_values()
base = ""
for k in mySeries:
base += k
file.write(base + "\n")
file.close()
您可以使用默认 itertools
库中的 itertools.permutaions
。您还可以指定组合中的字符数。
from itertools import permutations
charset = "0123456789abcdefghijklmnopqrstuvwxyz"
c = permutations(charset, 6)
with open('code.txt', 'w') as f:
for i in c:
f.write("".join(i) + '\n')
在我的计算机上运行大约 200 毫秒以创建排列列表,然后花费大量时间写入文件
这是一个组合问题,您试图从长度为 36 的字符集中获得长度为 6 的组合。这将产生大小为 36!/(30!*6!) 的输出。您可以参考 itertools 来解决像您这样的组合问题。可以参考itertools中的Combination函数 Documentation。建议不要使用 Python.
执行此类性能密集型计算我能想到的最快方法是使用 pypy3 和以下代码:
import functools
import time
from string import digits, ascii_lowercase
@functools.lru_cache(maxsize=128)
def main():
cl = []
cs = digits + ascii_lowercase
for letter in cs:
cl.append(letter)
ct = tuple(cl)
with open("codes.txt", "w") as file:
for p1 in ct:
for p2 in ct:
for p3 in ct:
for p4 in ct:
for p5 in ct:
for p6 in ct:
file.write(f"{p1}{p2}{p3}{p4}{p5}{p6}\n")
if __name__ == '__main__':
start = time.time()
main()
print(f"Done!\nTook {time.time() - start} seconds!")
写入速度约为 10-15MB/s。我相信总文件约为 15GB,因此生成需要 990-1500 秒。结果是在具有 1 个 3.4 ghz 服务器内核 CPU 的 unraid 虚拟机上,以及一个旧的 SATA3 SSD。使用 NVME 驱动器和更快的单核 CPU.
可能会获得更好的结果虽然这个 post 已经有 6 个答案,但我对其中任何一个都不满意,所以我决定贡献一个我自己的解决方案。
首先,请注意许多答案提供字母的 combinations
或 permutations
,但是 post 实际上需要字母表的笛卡尔积本身(重复 N 次, 其中 N=6)。有(此时)两个答案可以做到这一点,但是它们都 write
次数过多,导致性能不佳,并且还在循环的最热部分连接它们的中间结果(也降低了性能).
为了最大限度地优化,我提供了以下代码:
from string import digits, ascii_lowercase
from itertools import chain
ALPHABET = (digits + ascii_lowercase).encode("ascii")
def fast_brute_force():
# Define some constants to make the following sections more readable
base_size = 6
suffix_size = 4
prefix_size = base_size - suffix_size
word_size = base_size + 1
# define two containers
# word_blob - placeholder words, with hyphens in the unpopulated characters (followed by newline)
# sleds - a tuple of repeated bytes, used for substituting a bunch of characters in a batch
word_blob = bytearray(b"-" * base_size + b"\n")
sleds = tuple(bytes([char]) for char in ALPHABET)
# iteratively extend word_blob and sleds, and filling in unpopulated characters using the sleds
# in doing so, we construct a single "blob" that contains concatenated suffixes of the desired
# output with placeholders so we can quickly substitute in the prefix, write, repeat, in batches
for offset in range(prefix_size, base_size)[::-1]:
word_blob *= len(ALPHABET)
word_blob[offset::word_size] = chain.from_iterable(sleds)
sleds = tuple(sled * len(ALPHABET) for sled in sleds)
with open("output.txt", "wb") as f:
# I've expanded out the logic for substituting in the prefixes into explicit nested for loops
# to avoid both redundancy (reassigning the same value) and avoiding overhead associated with
# a recursive implementation
# I assert this below, so any changes in suffix_size will fail loudly
assert prefix_size == 2
for sled1 in sleds:
word_blob[0::word_size] = sled1
for sled2 in sleds:
word_blob[1::word_size] = sled2
# we write to the raw FileIO since we know we don't need buffering or other fancy
# bells and whistles, however in practice it doesn't seem that much faster
f.raw.write(word_blob)
该代码块中发生了很多神奇的事情,但简而言之:
- 我批处理写入,因此我一次写入
36**4
或1679616
个条目,因此上下文切换较少。 - 我使用字节数组切片/赋值,同时使用新前缀每批更新所有
1679616
个条目。 - 我对字节进行操作,写入原始文件 IO,扩展前缀分配的循环,以及其他小优化以避免 encoding/buffering/function 调用 overhead/other 性能影响。
请注意,除非您有一个 非常 快速的磁盘和较慢的 CPU,否则您不会从较小的优化中看到太多好处,可能只是写入批处理。
在我的系统上,生成和写入 14880348
文件大约需要 45 秒,这是写入我最慢的磁盘。在我的 NVMe 驱动器上,需要 6.868
秒。