s-m*_*m-e 10 python random generator python-3.x
我正在尝试展开一些嵌套循环,以(可能)更好的性能而牺牲内存.在我的场景中,我最终得到一个大约300M元素(元组)的列表,我必须以(或多或少)随机顺序产生.
在这个数量级上,random.shuffle(some_list)真的不再是那种方式了.
以下示例说明了该问题.请注意,在x86_64 Linux和CPython 3.6.4上,它将占用大约11 GB的内存.
def get_random_element():
some_long_list = list(range(0, 300000000))
for random_item in some_long_list:
yield random_item
Run Code Online (Sandbox Code Playgroud)
到目前为止,我的想法是简单地在每次迭代中生成一个随机索引,并从列表中无限地生成随机选取的元素(无限期).它可能会多次产生某些元素并完全跳过其他元素,这将是一个值得考虑的权衡.
在内存和CPU时间的合理范围内,我还有哪些其他选项可能只产生一次列表的每个元素?
这是 Fisher-Yates-Knuth 就地采样(https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
内存稳定~4Gb(是的,我用的是100000000)
# Fisher-Yates-Knuth sampling, in-place Durstenfeld version
import numpy as np
def swap(data, posA, posB):
if posA != posB:
data[posB], data[posA] = data[posA], data[posB]
def get_random_element(data, datalen):
pos = datalen
while pos > 0:
idx = np.random.randint(low=0, high=pos) # sample in the [0...pos) range
pos -= 1
swap(data, idx, pos)
yield data[pos]
length = 100000000
some_long_list = list(range(0, length))
gen = get_random_element(some_long_list, length)
for k in range(0, length):
print(next(gen))
Run Code Online (Sandbox Code Playgroud)
更新
为了速度,您可能还想内联 swap()