如果使用解释的Python 2.7.6,并尝试从链接到stdin的文件中读取大约5000万个整数(有符号,32位),如果它们排在一行,那么最快(性能)的方法是什么(最后没有\ n,空间分开?,或者可能以逗号分隔?优选地使用生成器和/或读取块,使得整个文件不被一次读入存储器,或者一次存储的所有50M整数的列表。该列表应减少为所有相邻元素xors (A[0]^A[1] + A[1]^A[2] + ... )
的总和,这些数字彼此非常接近,因此减少不会破坏32位有符号整数。
可以添加一个初始行,使其具有整数(n)和/或行长(L)。
我不熟悉python,我得到了不可接受的结果(> 30秒)。对于十分之一的限制,我做了大约6秒,所以我觉得我需要进一步改善这一点。
在我看来,如果他们分开了断线,这可能是可能的。有没有办法让python为readline()使用不同的分隔符?
尝试:
for ch in stdin.read()
,循环所有ch需要3秒钟,但是使用乘法构建整数然后手动减少需要太长时间。read(n)
,读取块,然后存储不完整的尾部,以便稍后使用split和map int,对于xrange,并按顺序减少块以构建缩减列表,但似乎也需要花费太长时间。 / LI>
我已经在更快的语言上完成了这一点,感谢,寻找解释的python答案。
这是我最好的代码,在某些情况下在18秒内运行,在其他情况下它太慢了。但它比我在累加器上使用乘法构建整数的版本更快。它也比每字节读取字节快:read(1)
。
def main():
n,l=map(int,raw_input().split())
#print n
#print l
r = 0 #result
p = 0 #previous
q = 0 #current
b = [] #buffer
for c in sys.stdin.read(): #character
if c == ' ':
q = int(''.join(b))
b = []
r += q ^ p #yes there is a bug with A[0] but lets optimize the loop for now
p = q
else:
b.append(c)
r += int(''.join(b)) ^ p
print r
main()
我可以看到它可以(可能)得到改进,如果有可能只初始化b一次然后不使用追加但实际访问索引,但是当我尝试b = [None]*12
时我在加入期间得到了一个RTE {{ 1}},需要一个范围内的连接,所以我暂时放弃了这个想法。也可以更快地完成我已经做过的工作。
更新
cant join None
这是快3倍(1000万可以在6秒内完成,但是50接超过30),对于5000万,它仍然太慢,IO似乎不是主要的瓶颈,而是数据处理。 / p>
可以使用常规列表代替deque,调用pop(0)而不是popleft。也可以不在每个循环上调用len(b),因为你在开头有n并且可以相减,但除此之外,这似乎是迄今为止最快的。
答案 0 :(得分:1)
读取字节流直到EOF。一旦你找到一个空格,将一个“数字”字节列表转换为一个整数,做你的异或,并重置列表。或者只是将数字附加到列表中,直到你确定一个空格。类似于以下未经测试的代码:
f = open("digits.txt", "rb")
try:
bytes = []
previous_num = None
byte = f.read(1)
while byte != "":
if byte != " ":
bytes.append(byte)
else:
# convert bytes to a number and reset list
current_num = int(''.join(map(str, bytes)))
if not previous_num:
previous_num = current_num
else:
# do your operation on previous and current number
bytes = []
byte = f.read(1)
finally:
f.close()
你可以通过读取大块的字节来优化它,而不是一次一个字节。另一种优化方法可能是为列表保留一种“nul”终结符,这是一个保持列表“长度”的索引。您可以在map
的开始/结束索引子集上执行bytes
操作,而不是在每个循环上清除它。但希望这证明了这一原则。
如果没有这个,您可以使用像sed
这样的Unix实用程序用空行替换空格并将sed
的输出传递给Python脚本,并从{{1}读取Python流,使用其(可能是优化的)一次读取一行的能力。
(但是,对于任何需要快速I / O的事情,Python可能是错误的答案。)
答案 1 :(得分:0)
我运行了这段代码:
WM_MOUSEWHEEL
得到了这些结果:
#!python2.7
from __future__ import print_function
import os, time
numbers = "100 69 38 24 17 11 3 22 "
print("Numbers:", numbers)
if not os.path.isfile('numbers.txt'):
with open('numbers.txt', 'w') as outfile:
n = 7*1000*1000
print("Repeating %d times..." % n)
print(numbers * n, file=outfile)
print("Starting read. Time:", time.strftime("%c"))
total = 0
with open('numbers.txt') as f:
prv = None
for nxt in f.read().split():
nxt = int(nxt)
if prv is not None:
total += prv ^ nxt
prv = nxt
print("Finished. Time:", time.strftime("%c"))
print("Total:", total)
在5年历史的MacBook Pro上,这个5600万(小)的数字在64秒左右 - 大约每秒100万个数字。你能告诉我们你的时间,以及你期望得到什么吗?
答案 2 :(得分:0)
如果您能找到比numpy.fromfile
但是,从文本文件中解析int比读取二进制数据要慢得多。这里有一些快速而肮脏的基准测试,使用两个具有相同~50M整数的文件。第一种是文本格式,另一种是二进制(使用numpy.ndarray.tofile
编写)
%timeit numpy.fromfile('numbers.txt', dtype=int, sep=' ')
1 loop, best of 3: 23.6 s per loop
%timeit numpy.fromfile('numbers.bin')
1 loop, best of 3: 2.55 s per loop
答案 3 :(得分:0)
这个怎么样
from itertools import tee, izip as zip
import re
def pairwise(iterable):
a,b = tee(iterable)
next(b,None)
return zip(a,b)
def process_data(data):
return sum( a^b for a,b in pairwise(data) )
def process_str_file_re(fname):
exp = re.compile(r"\d+")
with open(fname,"rb") as archi:
return process_data( int( data.group() ) for data in exp.finditer(archi.read()) )
当时不使用1个字符,而是使用专门处理字符操作的模块,如re