පයිතන් හි විශාල ගොනුවක පේළි ගණන ලාභදායී ලෙස ලබා ගන්නේ කෙසේද?


1037

මට විශාල ගොනුවක (පේළි සිය දහස් ගණනක්) පයිතන්වල රේඛා ගණනක් ලබා ගැනීමට අවශ්‍යයි. මතකය හා වේලාව අනුව වඩාත් කාර්යක්ෂම ක්‍රමය කුමක්ද?

මේ මොහොතේ මම කරන්නේ:

def file_len(fname):
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1

මීට වඩා හොඳ දෙයක් කළ හැකිද?


7
ඔබට නිශ්චිත රේඛා ගණනක් අවශ්‍යද? නැතිනම් දළ විශ්ලේෂණයක් ප්‍රමාණවත්ද?
pico

45
මෙම කේතය හිස් ලිපිගොනු සඳහා ක්‍රියා නොකරන බැවින් මම ලූප් සඳහා පෙර i = -1 එකතු කරමි.
මැකීක් සැවිකි

12
Le පුරාවෘත්තය: පිකෝ සිතන බව මම විශ්වාස කරමි, ගොනු විශාලත්වය ලබා ගන්න (සෙවීම (0,2) හෝ ඊට සමාන), දළ වශයෙන් රේඛීය දිග අනුව බෙදන්න. සාමාන්‍ය පේළි දිග අනුමාන කිරීමට ඔබට මුලදී පේළි කිහිපයක් කියවිය හැකිය.
ne න්

32
enumerate(f, 1)සහ ඉවත් කරන්න i + 1?
ඉයන් මැකිනන්

4
AnIanMackinnon හිස් ලිපිගොනු සඳහා ක්‍රියා කරයි, නමුත් for-loop ට පෙර i සිට 0 දක්වා ආරම්භ කළ යුතුය .
ස්කයි

Answers:


369

ඔබට ඊට වඩා හොඳක් ලබා ගත නොහැක.

සියල්ලට පසු, ඕනෑම විසඳුමකට සම්පූර්ණ ගොනුව කියවීමට, \nඔබ සතුව කොපමණ ප්‍රමාණයක් තිබේදැයි සොයා බලා එම ප්‍රති .ලය ලබා දිය යුතුය.

සම්පූර්ණ ගොනුව කියවීමෙන් තොරව ඔබට එය කිරීමට වඩා හොඳ ක්‍රමයක් තිබේද? විශ්වාස නැත ... හොඳම විසඳුම සැමවිටම I / O- බැඳී ඇත, ඔබට කළ හැකි හොඳම දෙය නම් ඔබ අනවශ්‍ය මතකය භාවිතා නොකරන බවට වග බලා ගැනීමයි, නමුත් එය ඔබ ආවරණය කර ඇති බව පෙනේ.


7
හරියටම, WC පවා ගොනුව හරහා කියවන නමුත් C හි එය බොහෝ දුරට ප්‍රශස්ත කර ඇත.
ඇල්ෆර් වේජ්

6
මා තේරුම් ගත් පරිදි පයිතන් ගොනුව IO සිදු කරනු ලබන්නේ C හරහාය. docs.python.org/library/stdtypes.html#file-objects
ටොමලක්

9
@ ටොමලක් එය රතු හුරුල්ලන් ය. පයිතන් සහ ඩබ්ලිව්සී එකම සිස්කල් නිකුත් කරන අතර, පයිතන්ට wc සතුව නැති ඔප්කෝඩ් පිටත් කර යැවීමේ උඩිස් ඇත.
bobpoekert

4
නියැදීමෙන් ඔබට දළ වශයෙන් රේඛා ගණනය කළ හැකිය. එය දහස් ගුණයකින් වේගවත් විය හැකිය. බලන්න: documentroot.com/2011/02/…
එරික් ඇරොනෙස්ටි

4
වෙනත් පිළිතුරු මගින් මෙම වර්ගීකරණ පිළිතුර වැරදියි, එබැවින් පිළිගත් ලෙස තබා ගැනීමට වඩා මකා දැමිය යුතුය.
Skippy le Grand Gourou

640

එක් පේළියක්, බොහෝ විට ඉතා වේගවත්:

num_lines = sum(1 for line in open('myfile.txt'))

8
එය එකතුවට සමාන වේ (1 අනුක්‍රමය) සෑම පේළියක්ම 1 ලෙස ගණන් ගනී. >>> [1 පරාසය සඳහා (10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] >>> එකතුව (පරාසය සඳහා 1 (10)) 10 >>>
ජේම්ස් සපම්

4
num_lines = sum (විවෘත පේළිය සඳහා 1 ('myfile.txt') නම් line.rstrip ()) හිස් රේඛා පෙරහන් කිරීම සඳහා
හොන්ග්.වු

62
අපි ගොනුවක් විවෘත කරන විට, අපි සියලු මූලද්‍රව්‍යයන් නැවත කියවූ පසු මෙය ස්වයංක්‍රීයව වසා දමනු ඇත්ද? එය 'වසා දැමීම' අවශ්‍යද? මෙම කෙටි ප්‍රකාශයේ අපට 'විවෘත ()' භාවිතා කළ නොහැකි යැයි මම සිතමි.
මන්නග්ජියා

16
Ann මන්නග්ජියා ඔබ නිවැරදියි, ගොනුව වැසෙන විට එය වැසෙන බවට වග බලා ගැනීම සඳහා 'විවෘත (ගොනු නාමය)' භාවිතා කිරීම වඩා හොඳය, ඊටත් වඩා හොඳ මෙය උත්සාහයක් හැර බ්ලොක් එකක් තුළ සිදු කිරීමකි, එහිදී සහ IOError ව්‍යතිරේකය විසි කරනු ලැබේ ගොනුව විවෘත කළ නොහැක.
බෝල්ට්ස්මාන් බ්‍රේන්

17
සැලකිල්ලට ගත යුතු තවත් දෙයක්: මෙය පේළි 300,000 ක පෙළ ගොනුවක දී ඇති මුල් ගැටළුවට වඩා තත්පර 0.04-0.05 ක් මන්දගාමී වේ
andrew

209

මතක සිතියම්ගත කළ ගොනුවක් වේගවත්ම විසඳුම වනු ඇතැයි මම විශ්වාස කරමි. මම කාර්යයන් හතරක් උත්සාහ කළෙමි: OP ( opcount) විසින් පළ කරන ලද ශ්‍රිතය ; ( simplecount) ගොනුවේ ඇති රේඛාවලට වඩා සරල පුනරාවර්තනයක් ; මතක සිතියම්ගත කර ඇති කියවීම් රේඛාව (mmap) ( mapcount); සහ මයිකොලා කරෙච්කෝ ( bufcount) විසින් පිරිනමන බෆරය කියවීමේ විසඳුම .

මම එක් එක් ශ්‍රිතය පස් වතාවක් ධාවනය කළ අතර, පේළි මිලියන 1.2 ක පෙළ ගොනුවක් සඳහා සාමාන්‍ය ධාවන කාලය ගණනය කළෙමි.

වින්ඩෝස් එක්ස්පී, පයිතන් 2.5, 2 ජීබී RAM, 2 GHz AMD ප්‍රොසෙසරය

මෙන්න මගේ ප්‍රති results ල:

mapcount : 0.465599966049
simplecount : 0.756399965286
bufcount : 0.546800041199
opcount : 0.718600034714

සංස්කරණය කරන්න : පයිතන් 2.6 සඳහා අංක:

mapcount : 0.471799945831
simplecount : 0.634400033951
bufcount : 0.468800067902
opcount : 0.602999973297

එබැවින් බෆර් කියවීමේ උපාය වින්ඩෝස් / පයිතන් 2.6 සඳහා වේගවත්ම බව පෙනේ

මෙන්න කේතය:

from __future__ import with_statement
import time
import mmap
import random
from collections import defaultdict

def mapcount(filename):
    f = open(filename, "r+")
    buf = mmap.mmap(f.fileno(), 0)
    lines = 0
    readline = buf.readline
    while readline():
        lines += 1
    return lines

def simplecount(filename):
    lines = 0
    for line in open(filename):
        lines += 1
    return lines

def bufcount(filename):
    f = open(filename)                  
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.read # loop optimization

    buf = read_f(buf_size)
    while buf:
        lines += buf.count('\n')
        buf = read_f(buf_size)

    return lines

def opcount(fname):
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1


counts = defaultdict(list)

for i in range(5):
    for func in [mapcount, simplecount, bufcount, opcount]:
        start_time = time.time()
        assert func("big_file.txt") == 1209138
        counts[func].append(time.time() - start_time)

for key, vals in counts.items():
    print key.__name__, ":", sum(vals) / float(len(vals))

1
මුළු මතක සිතියම්ගත ගොනුව මතකයට පටවා නැත. ඔබට අථත්‍ය මතක අවකාශයක් ලැබෙනු ඇත, මෙහෙයුම් පද්ධතිය අවශ්‍ය පරිදි RAM තුළට සහ පිටතට මාරු වේ. වින්ඩෝස් හි ඒවා හසුරුවන ආකාරය මෙන්න: msdn.microsoft.com/en-us/library/ms810613.aspx
රයන් ජින්ස්ට්‍රෝම්

1
කණගාටුයි, මතක සිතියම්ගත කළ ලිපිගොනු පිළිබඳ වඩාත් පොදු සඳහනක් මෙන්න: en.wikipedia.org/wiki/Memory-mapped_file සහ ඡන්දයට ස්තූතියි. :)
රයන් ජින්ස්ට්‍රෝම්

1
එය අතථ්‍ය මතකයක් පමණක් වුවද, එය හරියටම මෙම ප්‍රවේශය සීමා කරන අතර එම නිසා එය විශාල ලිපිගොනු සඳහා ක්‍රියා නොකරනු ඇත. මම එය මිලි ලීටර් 10 ට වැඩි ~ 1.2 Gb ගොනුවක් සමඟ අත්හදා බැලුවෙමි. රේඛා (wc -l සමඟ ලබාගත් පරිදි) සහ වින්ඩෝස් දෝෂයක් ලැබුණි: [දෝෂය 8] මෙම විධානය සැකසීමට ප්‍රමාණවත් ගබඩා නොමැත. ඇත්ත වශයෙන්ම, මෙය අද්දර නඩුවකි.
SilentGhost

6
තාත්වික කාල දත්ත සඳහා +1. 1024 * 1024 හි බෆරයේ ප්‍රමාණය ප්‍රශස්තද, නැතිනම් වඩා හොඳ එකක් තිබේද යන්න අපි දන්නවාද?
Kiv

29
එය wccount()වේගවත්ම gist.github.com/0ac760859e614cd03652
jfs

136

මගේ කීර්ති නාමය මඳක් ඉහළ යන තෙක් මට මෙය සමාන ප්‍රශ්නයක පළ කිරීමට සිදු විය (මට ගැසූ ඕනෑම කෙනෙකුට ස්තූතියි!).

මෙම සියලු විසඳුම් සැලකිය යුතු වේගයකින් ධාවනය කිරීම සඳහා එක් ක්‍රමයක් නොසලකා හරියි, එනම් නොනවතින (අමු) අතුරුමුහුණත භාවිතා කිරීම, බයිට්රේ භාවිතා කිරීම සහ ඔබේම බෆරින් කිරීම. (මෙය අදාළ වන්නේ පයිතන් 3 හි පමණි. පයිතන් 2 හි, අමු අතුරු මුහුණත පෙරනිමියෙන් භාවිතා කිරීමට හෝ භාවිතා කිරීමට ඉඩ ඇත, නමුත් පයිතන් 3 හි, ඔබ පෙරනිමියෙන් යුනිකෝඩ් වෙත පිවිසෙනු ඇත.)

කාල මෙවලමෙහි නවීකරණය කරන ලද අනුවාදයක් භාවිතා කරමින්, පහත දැක්වෙන කේතය ඉදිරිපත් කරන ඕනෑම විසඳුමකට වඩා වේගවත් (හා සුළු වශයෙන් පයිතොනික්) යැයි මම විශ්වාස කරමි:

def rawcount(filename):
    f = open(filename, 'rb')
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.raw.read

    buf = read_f(buf_size)
    while buf:
        lines += buf.count(b'\n')
        buf = read_f(buf_size)

    return lines

වෙනම උත්පාදක ශ්‍රිතයක් භාවිතා කරමින්, මෙය ස්මයිඩ් එකක් වේගයෙන් ධාවනය කරයි:

def _make_gen(reader):
    b = reader(1024 * 1024)
    while b:
        yield b
        b = reader(1024*1024)

def rawgencount(filename):
    f = open(filename, 'rb')
    f_gen = _make_gen(f.raw.read)
    return sum( buf.count(b'\n') for buf in f_gen )

ඉටර්ටූල් භාවිතා කරමින් පේළියේ උත්පාදක ප්‍රකාශන සමඟ මෙය සම්පූර්ණයෙන්ම කළ හැකිය, නමුත් එය අමුතු පෙනුමක් ලබා ගනී:

from itertools import (takewhile,repeat)

def rawincount(filename):
    f = open(filename, 'rb')
    bufgen = takewhile(lambda x: x, (f.raw.read(1024*1024) for _ in repeat(None)))
    return sum( buf.count(b'\n') for buf in bufgen )

මෙන්න මගේ වේලාවන්:

function      average, s  min, s   ratio
rawincount        0.0043  0.0041   1.00
rawgencount       0.0044  0.0042   1.01
rawcount          0.0048  0.0045   1.09
bufcount          0.008   0.0068   1.64
wccount           0.01    0.0097   2.35
itercount         0.014   0.014    3.41
opcount           0.02    0.02     4.83
kylecount         0.021   0.021    5.05
simplecount       0.022   0.022    5.25
mapcount          0.037   0.031    7.46

22
මම 100Gb + ලිපිගොනු සමඟ වැඩ කරන අතර, මම මෙතෙක් දැක ඇති එකම ශක්‍ය විසඳුම ඔබේ අමු ගණනය කිරීම් ය. ස්තූතියි!
soungalo

2
උප wccountවගු ෂෙල් wcමෙවලම සඳහා මෙම වගුවේ තිබේද?
ඇනෙන්ට්‍රොපික්

1
මෙය වෙනත් විවරණයකින්
Anentropic

4
ස්තූතියි @ මයිකල්-බේකන්, එය ඇත්තෙන්ම හොඳ විසඳුමක්. ඔයාට කරන්න පුළුවන් rawincountභාවිතා බලා විසඳුමක් අමුතු අඩු bufgen = iter(partial(f.raw.read, 1024*1024), b'')ඒකාබද්ධ වෙනුවට takewhileසහ repeat.
පීටර් එච්.

2
ඔහ්, අර්ධ ක්‍රියාකාරිත්වය, ඔව්, එය ලස්සන කුඩා වෙනස් කිරීමකි. එසේම, මම උපකල්පනය කළේ 1024 * 1024 පරිවර්තකයා විසින් ඒකාබද්ධ කර නියතයක් ලෙස සලකනු ඇති නමුත් එය ලේඛනගත කිරීමක් නොවන බවයි.
මයිකල් බේකන්

92

ඔබට උප ක්‍රියාවලියක් ක්‍රියාත්මක කර ධාවනය කළ හැකිය wc -l filename

import subprocess

def file_len(fname):
    p = subprocess.Popen(['wc', '-l', fname], stdout=subprocess.PIPE, 
                                              stderr=subprocess.PIPE)
    result, err = p.communicate()
    if p.returncode != 0:
        raise IOError(err)
    return int(result.strip().split()[0])

6
මෙහි කවුළු අනුවාදය කුමක් වනු ඇත්ද?
සයිලන්ට් හොස්ට්

1
ඒ සම්බන්ධයෙන් ඔබට මෙම SO ප්‍රශ්නය යොමු කළ හැකිය. stackoverflow.com/questions/247234/…
Ólafur Waage

7
ඇත්ත වශයෙන්ම, මගේ නඩුවේ (මැක් ඕඑස් එක්ස්) මෙය "ගොනුවේ x සඳහා (...)" නිපදවන රේඛා ගණන ගණනය කිරීම සඳහා 0.13s හා 0.5s අතර වේ. 1.0s එදිරිව str.find හෝ mmap.find . (මෙය පරීක්ෂා කිරීමට මා භාවිතා කළ ගොනුවේ පේළි මිලියන 1.3 ක් ඇත.)
බෙන්ඩින්

1
ඒ සඳහා කවචය සම්බන්ධ කිරීම අවශ්‍ය නොවේ. සංස්කරණය කළ පිළිතුර සහ එකතු කළ උදාහරණ කේතය;
nosklo

2
හරස් වේදිකාවක් නොවේ.
e-info128

43

යන්ත්‍ර / හර හරහා රේඛා ගණනය කිරීම බෙදා හැරීම සඳහා බහු සැකසුම් පුස්තකාලය භාවිතා කිරීම සඳහා පයිතන් වැඩසටහනක් මෙන්න. මගේ පරීක්ෂණය මගින් මූලික වින්ඩෝස් 64 සේවාදායකයක් භාවිතා කරමින් තත්පර 26 සිට තත්පර 7 දක්වා මිලියන 20 ක රේඛීය ගොනුවක් ගණනය කිරීම වැඩි දියුණු කරයි. සටහන: මතක සිතියම්කරණය භාවිතා නොකිරීම දේවල් මන්දගාමී කරයි.

import multiprocessing, sys, time, os, mmap
import logging, logging.handlers

def init_logger(pid):
    console_format = 'P{0} %(levelname)s %(message)s'.format(pid)
    logger = logging.getLogger()  # New logger at root level
    logger.setLevel( logging.INFO )
    logger.handlers.append( logging.StreamHandler() )
    logger.handlers[0].setFormatter( logging.Formatter( console_format, '%d/%m/%y %H:%M:%S' ) )

def getFileLineCount( queues, pid, processes, file1 ):
    init_logger(pid)
    logging.info( 'start' )

    physical_file = open(file1, "r")
    #  mmap.mmap(fileno, length[, tagname[, access[, offset]]]

    m1 = mmap.mmap( physical_file.fileno(), 0, access=mmap.ACCESS_READ )

    #work out file size to divide up line counting

    fSize = os.stat(file1).st_size
    chunk = (fSize / processes) + 1

    lines = 0

    #get where I start and stop
    _seedStart = chunk * (pid)
    _seekEnd = chunk * (pid+1)
    seekStart = int(_seedStart)
    seekEnd = int(_seekEnd)

    if seekEnd < int(_seekEnd + 1):
        seekEnd += 1

    if _seedStart < int(seekStart + 1):
        seekStart += 1

    if seekEnd > fSize:
        seekEnd = fSize

    #find where to start
    if pid > 0:
        m1.seek( seekStart )
        #read next line
        l1 = m1.readline()  # need to use readline with memory mapped files
        seekStart = m1.tell()

    #tell previous rank my seek start to make their seek end

    if pid > 0:
        queues[pid-1].put( seekStart )
    if pid < processes-1:
        seekEnd = queues[pid].get()

    m1.seek( seekStart )
    l1 = m1.readline()

    while len(l1) > 0:
        lines += 1
        l1 = m1.readline()
        if m1.tell() > seekEnd or len(l1) == 0:
            break

    logging.info( 'done' )
    # add up the results
    if pid == 0:
        for p in range(1,processes):
            lines += queues[0].get()
        queues[0].put(lines) # the total lines counted
    else:
        queues[0].put(lines)

    m1.close()
    physical_file.close()

if __name__ == '__main__':
    init_logger( 'main' )
    if len(sys.argv) > 1:
        file_name = sys.argv[1]
    else:
        logging.fatal( 'parameters required: file-name [processes]' )
        exit()

    t = time.time()
    processes = multiprocessing.cpu_count()
    if len(sys.argv) > 2:
        processes = int(sys.argv[2])
    queues=[] # a queue for each process
    for pid in range(processes):
        queues.append( multiprocessing.Queue() )
    jobs=[]
    prev_pipe = 0
    for pid in range(processes):
        p = multiprocessing.Process( target = getFileLineCount, args=(queues, pid, processes, file_name,) )
        p.start()
        jobs.append(p)

    jobs[0].join() #wait for counting to finish
    lines = queues[0].get()

    logging.info( 'finished {} Lines:{}'.format( time.time() - t, lines ) )

ප්‍රධාන මතකයට වඩා විශාල ගොනු සමඟ මෙය ක්‍රියා කරන්නේ කෙසේද? උදාහරණයක් ලෙස 4GB RAM සහ කෝර් 2 ක් සහිත පද්ධතියක 20GB ගොනුවක්
බ්‍රයන් මින්ටන්

දැන් පරීක්ෂා කිරීම අසීරු ය, නමුත් මම සිතන්නේ එය ගොනුව පිටතින් හා පිටතින් පිට කරයි.
මාර්ට්ලාර්ක්

5
මෙය ඉතා පිළිවෙලට කේතය. බහු ප්‍රොසෙසර භාවිතා කිරීම වේගවත් බව දැනගත් විට මම පුදුමයට පත් වීමි. IO එක බාධකයක් වනු ඇතැයි මම සිතුවෙමි. පැරණි පයිතන් අනුවාද වලදී, 21 වන පේළියට int () වැනි chunk = int ((fSize / process)) + 1
අවශ්‍යයි

එය සියලුම ගොනුව මතකයට පටවනවාද? පරිගණකයේ ඇති බැටළුවාගේ ප්‍රමාණයට වඩා විශාල ගින්නක් ගැන කුමක් කිව හැකිද?
pelos

ලිපිගොනු අථත්ය මතකයට සිතියම් ගත කර ඇති බැවින් ගොනුවේ ප්රමාණය සහ සැබෑ මතකයේ ප්රමාණය සාමාන්යයෙන් සීමා කිරීමක් නොවේ.
මාර්ට්ලාර්ක්

19

නවීන ශ්‍රිතය භාවිතා කරමින් මෙම පිළිතුරට සමාන එක්-පේළි බැෂ් විසඳුමක් subprocess.check_output:

def line_count(filename):
    return int(subprocess.check_output(['wc', '-l', filename]).split()[0])

මෙම පිළිතුර ලිනක්ස් / යුනික්ස් භාවිතා කරන්නන් සඳහා මෙම ත්‍රෙඩ් එකේ ඉහළ ස්ථානයකට ඡන්දය දිය යුතුය. හරස් වේදිකා විසඳුමක බහුතර මනාපයන් තිබියදීත්, මෙය ලිනක්ස් / යුනික්ස් හි විශිෂ්ට ක්‍රමයකි. මිලියන 184 ක සීඑස්වී ගොනුවක් සඳහා මට දත්ත සාම්පල ලබා ගත යුතු අතර, එය හොඳම ධාවන කාලය සපයයි. වෙනත් පිරිසිදු පයිතන් විසඳුම් සාමාන්‍යයෙන් තත්පර 100+ ක් ගත වන අතර උපසිරැසි ඇමතුමට wc -lතත්පර 5 ක් ගතවේ.
ෂාන් ඩූ

shell=Trueආරක්ෂාවට නරකයි, එය වළක්වා ගැනීම වඩා හොඳය.
ඇලෙක්සි වස්නොව්

16

මම readlinesපහත පරිදි පයිතන්ගේ ගොනු වස්තු ක්‍රමය භාවිතා කරමි :

with open(input_file) as foo:
    lines = len(foo.readlines())

මෙය ගොනුව විවෘත කරයි, ගොනුවේ පේළි ලැයිස්තුවක් සාදයි, ලැයිස්තුවේ දිග ගණනය කරයි, එය විචල්‍යයකට ඉතිරි කර ගොනුව නැවත වසා දමයි.


8
මෙය මතකයට එන පළමු ක්‍රමවලින් එකක් වුවද, එය බොහෝ විට මතක ශක්තිය කාර්යක්ෂම නොවනු ඇත, විශේෂයෙන් 10 GB දක්වා ලිපිගොනු වල රේඛා ගණනය කිරීම (මා මෙන්), එය සැලකිය යුතු අවාසියකි.
ස්ටීන් ෂොට්

ටයිම්ෂීප් මෙය කුඩා රේඛා බොහොමයක් (කියන්න, බිලියන ගණනක්) සහිත ලිපිගොනු සඳහාද, නැතහොත් අතිශය දිගු රේඛා ඇති ලිපිගොනු සඳහාද (කියන්න, එක් පේළියකට ගිගාබයිට්)?
රොබට්

මා අසන හේතුව නම්, අතරමැදි ලැයිස්තුවක් නිර්මාණය නොකිරීම මගින් සම්පාදකයාට මෙය ප්‍රශස්තිකරණය කළ හැකි බව පෙනේ.
රොබට්

mdmityugov Per Python docs, xreadlines2.3 සිට අවලංගු කර ඇත, එය නැවත නැවත ක්‍රියාකරවන්නෙකු ආපසු ලබා දෙන බැවින්. for line in fileප්‍රකාශිත ආදේශනය වේ. බලන්න: docs.python.org/2/library/stdtypes.html#file.xreadlines
කුම්බා

13

පිරිසිදු පයිතන් භාවිතයෙන් මා සොයාගත් වේගවත්ම දේ මෙයයි. 2 ** 16 මගේ පරිගණකයේ මිහිරි ස්ථානයක් ලෙස පෙනුනද, බෆරය සැකසීමෙන් ඔබට අවශ්‍ය ඕනෑම මතක ප්‍රමාණයක් භාවිතා කළ හැකිය.

from functools import partial

buffer=2**16
with open(myfile) as f:
        print sum(x.count('\n') for x in iter(partial(f.read,buffer), ''))

මට මෙහි පිළිතුර හමු විය පයිතන්ට වඩා C ++ හි stdin වෙතින් රේඛා කියවීම මන්දගාමී වන්නේ ඇයි? එය ඉතා සුළු වශයෙන් වෙනස් කළා. පේළි ඉක්මණින් ගණනය කරන්නේ කෙසේද යන්න තේරුම් ගැනීමට එය ඉතා හොඳ කියවීමකි, නමුත් wc -lසියල්ලටම වඩා 75% ක් පමණ වේගවත්ය.


12

මෙන්න මම භාවිතා කරන දේ, පිරිසිදු බව පෙනේ:

import subprocess

def count_file_lines(file_path):
    """
    Counts the number of lines in a file using wc utility.
    :param file_path: path to file
    :return: int, no of lines
    """
    num = subprocess.check_output(['wc', '-l', file_path])
    num = num.split(' ')
    return int(num[0])

යාවත්කාලීන කිරීම: මෙය පිරිසිදු පයිතන් භාවිතා කිරීමට වඩා සුළු වේගයකින් සිදු වන නමුත් මතක භාවිතය සඳහා වන වියදමෙන්. උප ක්‍රියාවලිය මඟින් ඔබේ විධානය ක්‍රියාත්මක කරන අතරම මව් ක්‍රියාවලියට සමාන මතක සටහන් සහිත නව ක්‍රියාවලියක් සිදු කරයි.


1
පැති සටහනක් ලෙස, මෙය ඇත්ත වශයෙන්ම වින්ඩෝස් මත ක්‍රියා නොකරනු ඇත.
බ්‍රැම් වැන්රෝයි

මූලික උපයෝගීතා වින්ඩෝස් stackoverflow.com/questions/247234/… සඳහා "wc" සපයයි . ඔබේ කේතය ප්‍රොඩක් තුළ ලිනක්ස් වලින් ක්‍රියාත්මක වන්නේ නම් ඔබේ වින්ඩෝස් පෙට්ටියේ ලිනක්ස් වීඑම් එකක් භාවිතා කළ හැකිය.
radtek

හෝ ඩබ්ලිව්එස්එල්, ඕනෑම වීඑම් එකක් ගැන ඉහළින්ම උපදෙස් දෙනුයේ ඔබ කරන එකම දෙය නම් මේ වගේ දේවල් නම්. :-)
බ්‍රැම් වැන්රෝයි

ඔව් ඒක වැඩ කරනවා. මම වින්ඩෝස් මිනිහෙක් නොවුනත් ගොල්ජිං වලින් මම ඉගෙන ගත්තේ ලිනක්ස් සඳහා WSL = වින්ඩෝස් උප
පද්ධතියයි

3
python3.7: උපප්‍රොසෙස් ආපසු බයිට්, එබැවින් කේතය මේ ආකාරයට පෙනේ: int (subprocess.check_output (['wc', '-l', file_path]). විකේතනය ("utf-8"). lstrip (). භේදය (" ") [0])
ඇලෙක්සි ඇලෙක්සෙන්කා

11
def file_len(full_path):
  """ Count number of lines in a file."""
  f = open(full_path)
  nr_of_lines = sum(1 for line in f)
  f.close()
  return nr_of_lines

9

මෙම අනුවාදය සමඟ මට කුඩා (4-8%) වැඩි දියුණුවක් ඇති අතර එය නියත බෆරයක් නැවත භාවිතා කරයි, එම නිසා එය කිසිදු මතකයක් හෝ GC පොදු කාර්යයක් මඟ හැරිය යුතුය:

lines = 0
buffer = bytearray(2048)
with open(filename) as f:
  while f.readinto(buffer) > 0:
      lines += buffer.count('\n')

ඔබට ස්වාරක්ෂක ප්‍රමාණය සමඟ සෙල්ලම් කළ හැකි අතර සුළු දියුණුවක් දැකිය හැකිය.


හොඳයි. \ N වලින් අවසන් නොවන ලිපිගොනු සඳහා ගණනය කිරීම සඳහා, බෆරය සහ බෆරය නම්
ලූපයෙන්

දෝෂයක්: අවසාන වටයේ බෆරය පිරිසිදු නොවිය හැක.
ජේ

බෆර අතර එක් කොටසක් \ සමඟ අවසන් වන අතර අනෙක් කොටස n සමඟ ආරම්භ වන්නේ නම් කුමක් කළ යුතුද? එමඟින් එහි එක් නව පේළියක් මග හැරෙනු ඇත, එක් එක් කැබැල්ලේ අවසානය සහ ආරම්භය ගබඩා කිරීම සඳහා මම විචල්‍යයන්ට යොමු කරමි, නමුත් එය ස්ක්‍රිප්ටයට වැඩි කාලයක් එකතු කළ හැකිය = (
pelos

9

කයිල්ගේ පිළිතුර

num_lines = sum(1 for line in open('my_file.txt'))

බොහෝ විට හොඳම, මේ සඳහා විකල්පයක් වේ

num_lines =  len(open('my_file.txt').read().splitlines())

දෙකෙහිම කාර්ය සාධනය සංසන්දනය කිරීම මෙන්න

In [20]: timeit sum(1 for line in open('Charts.ipynb'))
100000 loops, best of 3: 9.79 µs per loop

In [21]: timeit len(open('Charts.ipynb').read().splitlines())
100000 loops, best of 3: 12 µs per loop

9

එක් පේළියේ විසඳුම:

import os
os.system("wc -l  filename")  

මගේ ස්නිපටය:

>>> os.system('wc -l *.txt')

0 bar.txt
1000 command.txt
3 test_file.txt
1003 total

හොඳ අදහසක්, අවාසනාවකට මෙය වින්ඩෝස් මත ක්‍රියා නොකරයි.
කිම්

3
ඔබට පයිතන් සැරිසැරීමට අවශ්‍ය නම්, කවුළුවලට සමුගන්න. මාව විශ්වාස කරන්න ඔබ කවදා හෝ මට ස්තූති කරනු ඇත.
TheExorcist

6
මෙය ක්‍රියාත්මක වන්නේ කවුළු මත පමණක් බව මම සලකමි. මම ලිනක්ස් / යුනික්ස් ස්ටක් එකක වැඩ කිරීමට කැමැත්තෙමි, නමුත් මෘදුකාංග IMHO ලිවීමේදී විවිධ මෙහෙයුම් පද්ධති යටතේ ක්‍රියාත්මක වන විට වැඩසටහනකට ඇතිවිය හැකි අතුරු ආබාධ සලකා බැලිය යුතුය. OP ඔහුගේ වේදිකාව ගැන සඳහන් නොකළ නිසා සහ යමෙකු මෙම විසඳුම ගූගල් හරහා ඉදිරිපත් කර එය පිටපත් කළහොත් (වින්ඩෝස් පද්ධතියකට තිබිය හැකි සීමාවන් නොදැන), මට සටහන එකතු කිරීමට අවශ්‍ය විය.
කිම්

ඔබට ප්‍රතිදානය os.system()විචල්‍යයට සුරැකිය නොහැකි අතර එය කෙසේ හෝ පසු සැකසුම් කරන්න.
ඒ සේ

ඔබ නිවැරදියි නමුත් එය ඉතිරි වේද නැද්ද යන ප්‍රශ්නය අසනු නොලැබේ.ඔබ සන්දර්භය තේරුම් ගෙන ඇති බව මම අනුමාන කරමි.
TheExorcist

6

ඉහත ක්‍රම සම්පූර්ණ කිරීම සඳහා මම ගොනු ආදාන මොඩියුලය සමඟ ප්‍රභේදයක් උත්සාහ කළෙමි:

import fileinput as fi   
def filecount(fname):
        for line in fi.input(fname):
            pass
        return fi.lineno()

ඉහත සඳහන් සියලු ක්‍රම සඳහා මිලි 60 රේඛා ගොනුවක් සම්මත කළේය:

mapcount : 6.1331050396
simplecount : 4.588793993
opcount : 4.42918205261
filecount : 43.2780818939
bufcount : 0.170812129974

ගොනු ආදානය එතරම් නරක බවත් අනෙක් සියලුම ක්‍රමවලට වඩා පරිමාණයන් නරක බවත් මට පුදුමයකි ...


6

මට නම් මෙම ප්‍රභේදය වේගවත්ම වේ:

#!/usr/bin/env python

def main():
    f = open('filename')                  
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.read # loop optimization

    buf = read_f(buf_size)
    while buf:
        lines += buf.count('\n')
        buf = read_f(buf_size)

    print lines

if __name__ == '__main__':
    main()

හේතු: පේළියෙන් රේඛාව කියවීමට වඩා වේගයෙන් බෆර් කිරීම string.countඉතා වේගවත් වේ


1
නමුත් එසේ ද? අවම වශයෙන් OSX / python2.5 මත OPit අනුවාදය timeit.py අනුව 10% ක් පමණ වේගවත් වේ.
dF.

අවසාන පේළිය '\ n' වලින් අවසන් නොවන්නේ නම් කුමක් කළ යුතුද?
tzot

1
ඔබ එය පරීක්‍ෂා කළේ කෙසේදැයි මම නොදනිමි, dF, නමුත් මගේ යන්ත්‍රයේ එය වෙනත් විකල්පයකට වඩා ~ 2.5 ගුණයකින් මන්දගාමී වේ.
SilentGhost

34
එය වේගවත්ම බව ඔබ පවසන අතර ඔබ එය අත්හදා බලා නොමැති බව ප්‍රකාශ කරන්න. එතරම් විද්‍යාත්මක නොවේ ද? :)
flafur Waage

රයන් ජින්ස්ට්‍රෝම් විසින් සපයන ලද විසඳුම සහ සංඛ්‍යාලේඛන පහත බලන්න. ජේ. එෆ්. සෙබස්තියන්ගේ ප්‍රකාශය සහ එකම පිළිතුරේ සබැඳිය බලන්න.
ෂෙරිල්හෝමන්

5

මෙම කේතය කෙටි හා පැහැදිලි ය. එය බොහෝ විට හොඳම ක්‍රමයයි:

num_lines = open('yourfile.ext').read().count('\n')

6
ඔබ ගොනුව ද වසා දැමිය යුතුය.
rsm

6
එය මුළු ගොනුවම මතකයට පටවනු ඇත.
Ivelin

4

මම බෆර් නඩුව මේ ආකාරයට වෙනස් කර ඇත:

def CountLines(filename):
    f = open(filename)
    try:
        lines = 1
        buf_size = 1024 * 1024
        read_f = f.read # loop optimization
        buf = read_f(buf_size)

        # Empty file
        if not buf:
            return 0

        while buf:
            lines += buf.count('\n')
            buf = read_f(buf_size)

        return lines
    finally:
        f.close()

දැන් හිස් ලිපිගොනු සහ අවසාන පේළිය (without n නොමැතිව) ගණනය කෙරේ.


සමහර විට ඔබ වෙනස් කළ දේ සහ කුමක් සඳහාද යන්න පැහැදිලි කරන්න (හෝ කේතයේ අදහස් එක් කරන්න); ඔබගේ කේතයේ ඇතුළත සිටින අයට වඩා පහසු යමක් ලබා දිය හැකිය (මොළයේ කේතය "විග්‍රහ කිරීමට" වඩා).
ස්ටයික්සි

මම හිතන්නේ Python read_f දී දේශීය විචල්ය බැලීම කරන්න ඉඩ ලබා දෙන අතර, කම්බියක් ප්රශස්තිකරණය python.org/doc/essays/list2str
රතු හඩකැවීම



3
def line_count(path):
    count = 0
    with open(path) as lines:
        for count, l in enumerate(lines, start=1):
            pass
    return count

3

යමෙකුට ලිනක්ස් හි පයිතන් හි රේඛීය ගණන ලාභදායී ලෙස ලබා ගැනීමට අවශ්‍ය නම්, මම මෙම ක්‍රමය නිර්දේශ කරමි:

import os
print os.popen("wc -l file_path").readline().split()[0]

file_path වියුක්ත ගොනු මාර්ගය හෝ සාපේක්ෂ මාර්ගය විය හැකිය. මෙය උපකාරී වේ යැයි සිතමි.


2

මේ ගැන කුමක් කිව හැකිද?

def file_len(fname):
  counts = itertools.count()
  with open(fname) as f: 
    for _ in f: counts.next()
  return counts.next()

2

කොහොමද මේ?

import fileinput
import sys

counter=0
for line in fileinput.input([sys.argv[1]]):
    counter+=1

fileinput.close()
print counter

2

මෙම එක් ලයිනර් ගැන කෙසේද:

file_length = len(open('myfile.txt','r').read().split('\n'))

පේළි 3900 ක ගොනුවක වේලාව සැකසීමට තත්පර 0.003 ක් ගතවේ

def c():
  import time
  s = time.time()
  file_length = len(open('myfile.txt','r').read().split('\n'))
  print time.time() - s

2
def count_text_file_lines(path):
    with open(path, 'rt') as file:
        line_count = sum(1 for _line in file)
    return line_count

එය වැරදියි කියා ඔබ සිතන්නේ නම් කරුණාකර එහි ඇති වැරැද්ද කුමක්දැයි ඔබට පැහැදිලි කළ හැකිද? එය මට වැඩ කළා. ස්තූතියි!
jciloa

මෙම පිළිතුර අවතක්සේරු කළේ ඇයිද යන්න ගැන මම උනන්දු වෙමි. එය ගොනුව රේඛා මගින් පුනරාවර්තනය කර ඒවා සාරාංශ කරයි. මම එයට කැමතියි, එය කෙටි වන අතර කාරණය නම්, එහි ඇති වරද කුමක්ද?
cessor

2

සරල ක්‍රමය:

1)

>>> f = len(open("myfile.txt").readlines())
>>> f

430

2)

>>> f = open("myfile.txt").read().count('\n')
>>> f
430
>>>

3)

num_lines = len(list(open('myfile.txt')))

3
මෙම උදාහරණයේ ගොනුව වසා නැත.
මැකීජ් එම්

9
OP ට මතකය කාර්යක්ෂම යමක් අවශ්‍ය විය. මෙය අනිවාර්යයෙන්ම නොවේ.
ඇන්ඩි කාල්සන්

1

ගොනුවක් විවෘත කිරීමේ ප්‍රති result ලය අනුකාරකයක් වන අතර එය අනුක්‍රමයකට පරිවර්තනය කළ හැකිය, එහි දිග ඇත:

with open(filename) as f:
   return len(list(f))

මෙය ඔබගේ පැහැදිලි පුඩුවට වඩා සංක්ෂිප්ත වන අතර එය වළක්වයි enumerate.


10
එයින් අදහස් කරන්නේ 100 Mb ගොනුවක් මතකයට කියවිය යුතු බවයි.
සයිලන්ට් හොස්ට්

ඔව්, හොඳ කරුණක්, වේගය (මතකයට වඩා වෙනස්) ගැන මම කල්පනා කළත්. මෙය සිදුකරන අනුකාරකයක් සෑදීමට බොහෝ විට හැකි නමුත් මම සිතන්නේ එය ඔබේ විසඳුමට සමාන වනු ඇත.
ඇන්ඩ rew ජැෆේ

6
-1, එය මතකය පමණක් නොව, මතකයේ ලැයිස්තුවක් සෑදිය යුතුය.
orip

0

ඔබට os.pathමොඩියුලය පහත පරිදි භාවිතා කළ හැකිය :

import os
import subprocess
Number_lines = int( (subprocess.Popen( 'wc -l {0}'.format( Filename ), shell=True, stdout=subprocess.PIPE).stdout).readlines()[0].split()[0] )

, Filenameගොනුවේ නිරපේක්ෂ මාර්ගය කොහිද ?


1
මෙම පිළිතුරට කුමක් කළ os.pathයුතුද?
moi

0

ගොනුව මතකයට ගැලපෙන්නේ නම්, එසේ නම්

with open(fname) as f:
    count = len(f.read().split(b'\n')) - 1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.