Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 优化IO性能-读取由空格分隔的5000万个整数_Python_Performance_Csv_Io - Fatal编程技术网

Python 优化IO性能-读取由空格分隔的5000万个整数

Python 优化IO性能-读取由空格分隔的5000万个整数,python,performance,csv,io,Python,Performance,Csv,Io,如果使用解释型Python 2.7.6,并尝试从链接到stdin的文件中读取大约5000万个整数(有符号,32位),那么如果这些整数是以单行(结尾没有\n)、空格分隔还是逗号分隔的,那么最快的(性能)方法是什么?最好使用生成器和/或分块读取,以便不将整个文件一次读入内存,或一次存储所有50M整数的列表。列表应缩减为所有相邻元素XOR的总和(A[0]^A[1]+A[1]^A[2]+…),这些数字彼此非常接近,因此缩减不会中断32位带符号整数 可以添加初始行,使其具有整数数(n)和/或行长度(L)

如果使用解释型Python 2.7.6,并尝试从链接到stdin的文件中读取大约5000万个整数(有符号,32位),那么如果这些整数是以单行(结尾没有\n)、空格分隔还是逗号分隔的,那么最快的(性能)方法是什么?最好使用生成器和/或分块读取,以便不将整个文件一次读入内存,或一次存储所有50M整数的列表。列表应缩减为所有相邻元素XOR的总和
(A[0]^A[1]+A[1]^A[2]+…)
,这些数字彼此非常接近,因此缩减不会中断32位带符号整数


可以添加初始行,使其具有整数数(n)和/或行长度(L)

我不精通python,而且我得到了不可接受的结果(>30秒)。对于十分之一的极限,我只需要6秒,所以我觉得我需要进一步改进

在我看来,如果他们以断线分开,这可能是可能的。有没有办法告诉python对readline()使用不同的分隔符

尝试:

  • 对于stdin.read()
    中的ch,循环所有ch需要3秒钟,但是使用乘法生成整数,然后手动进行缩减需要花费太长时间
  • read(n)
    ,分块读取,然后使用split和map int存储不完整的尾部以备以后使用,对于xrange和reduce,按顺序在块上构建缩减列表,但似乎再次花费太长时间
我已经在更快的语言上完成了这项工作,谢谢,正在寻找解释python的答案

这是我最好的代码,在某些情况下运行18秒,在其他情况下运行太慢。但它比我在累加器上用乘法构建整数的版本要快。它也比逐字节读取快:
read(1)

我可以看到,如果可以只初始化b一次,然后不使用append,而是实际访问索引,那么它可能(可能)会得到改进,但是当我尝试
b=[None]*12
时,我在加入过程中得到了一个RTE
不能加入任何人
,需要一个范围内的加入,所以我暂时放弃了这个想法。还有更快的功能来完成我已经完成的工作

更新:

import re
import sys

from collections import deque

def main():
    n,l=map(int,raw_input().split())
    #print n
    #print l

    r = 0
    p = 0
    q = 0

    b = sys.stdin.read(l)

    b = deque(b.rsplit(' ',4000000))
    n = len(b)
    while n == 4000001:
        c = b.popleft()
        b = map(int,b)
        for i in xrange(n-2,0,-1):
            r += b[i] ^ b[i-1]

        m = b[0]
        b = deque(c.rsplit(' ',3999999))
        b.append(m)
        n = len(b)


    b = map(int,b)
    for i in xrange(n-1,0,-1):
        r += b[i] ^ b[i-1]

    print r
main()
这是3倍的速度(1000万可以在6秒钟内完成,但50可以超过30),对于5000万,速度仍然太慢,IO似乎不是主要瓶颈,而是数据处理


可以使用常规列表代替deque,调用pop(0)而不是popleft。也可以不在每个循环中调用len(b),因为开始时有n,可以进行减法,但除此之外,这似乎是迄今为止最快的。读取字节流直到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”终止符,一种保持列表“长度”的索引。不是在每个循环中清除它,而是在
字节的开始/结束索引子集上执行
映射
操作。但希望这能证明这一原则

除此之外,您可能还可以使用Unix实用程序(如
sed
)将空格替换为换行符,并将
sed
的输出通过管道传输到Python脚本,让Python从
stdin
流中读取,同时使用其(可能是优化的)能力一次读取一行

(但实际上,对于任何需要快速I/O的东西,Python可能是错误的答案。)

我运行了以下代码:

#!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)
得到了这些结果:

$ python2.7 test.py
Numbers: 100 69 38 24 17 11 3 22
Starting read. Time: Fri Feb  3 19:20:32 2017
Finished. Time: Fri Feb  3 19:21:36 2017
Total: 2603999886

这是5600万(小)个数字,在一台5年历史的MacBookPro电脑上,在64秒左右的时间内——大约每秒100万个数字。您能告诉我们您的时间安排,以及您希望得到什么吗?

如果您能找到比我们更快的实现,我会感到惊讶

然而,从文本文件解析int要比仅仅读取二进制数据慢得多。下面是一些快速而肮脏的基准测试,使用两个具有相同~50M整数的文件。第一种是文本格式,另一种是二进制格式(使用
numpy.ndarray.tofile
编写)

这个怎么样

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()) )

不要一次使用一个字符,而是使用一个专门处理字符的模块,如
re

这似乎不是一个与[csv]相关的问题,因为您说的数字是空格分隔的。你能给我们看一下你迄今为止试过的代码吗?也许是最快的版本?问题是它可以用逗号分隔(如果有任何东西处理逗号而不是空格,我怀疑),如果文件是二进制格式的,你可以使用
array.fromfile
,这应该很快。您是否可以控制文件的写入方式?这意味着每个32位id必须存储一个整数,对吗?不,该文件是csv/空格分隔文本“可以添加初始行,使其具有整数数(n)和/或行长度(L)。”-要使它们成为什么?希望至少得到哦,不。首先要正确,然后要快速。总是,只是个小虫子。。。做得很好,速度很快,但仍然不够快。我把open改为open('rb'),并下降到37秒左右。这篇链接文章中的建议似乎非常有效。值得注意的是,当他转向python 3时,他使用了自己的一种模式,获得了非常好的性能。我尝试了read(1),但得到的结果比在read()中为c做
,我不确定我是否理解您的映射块想法。请看这篇文章,了解一些想法:
%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
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()) )