যেহেতু আমার পুরানো কাজটি প্রায়শই 1 মিলিয়ন লাইন ফিক্সউইথ ডেটা পরিচালনা করে, আমি পাইথন ব্যবহার শুরু করার পরে এই বিষয়ে গবেষণা করেছি।
এখানে 2 ধরণের ফিক্সডউইথ থাকে
- এএসসিআইআই ফিক্সডউইথ (আসকি চরিত্রের দৈর্ঘ্য = 1, ডাবল-বাইট এনকোডেড অক্ষরের দৈর্ঘ্য = 2)
- ইউনিকোড ফিক্সড ওয়াইড (আসকি চরিত্র এবং ডাবল-বাইট এনকোডেড অক্ষরের দৈর্ঘ্য = 1)
যদি রিসোর্স স্ট্রিংগুলি সমস্ত এএসসিআই অক্ষর সমন্বিত থাকে, তবে ASCII ফিক্সডওয়েথ = ইউনিকোড ফিক্সড উইথ
ভাগ্যক্রমে, স্ট্রিং এবং বাইট পাই 3-তে পৃথক, যা ডাবল-বাইট এনকোডেড অক্ষর (ডিম্বক, বিগ 5, ইউক-জেপি, শিফট-জিস, ইত্যাদি) নিয়ে কাজ করার সময় প্রচুর বিভ্রান্তি হ্রাস করে।
"এএসসিআইআই ফিক্সড উইথ" প্রক্রিয়াকরণের জন্য স্ট্রিংটি সাধারণত বাইটে রূপান্তরিত হয় এবং তারপরে বিভক্ত হয়।
তৃতীয় পক্ষের মডিউলগুলি
মোট লাইনেকাউন্ট = 1 মিলিয়ন, লাইনলিংথ = 800 বাইট, ফিক্সড ওয়েইথআরগস = (10,25,4, ....) আমদানি না করে আমি লাইনটি প্রায় 5 উপায়ে বিভক্ত করে নীচের উপসংহারটি পেয়েছি:
- কাঠামো দ্রুততম (1x)
- কেবল লুপ, প্রাক-প্রক্রিয়াজাতকরণ নয় স্থিরউইথআরগস সবচেয়ে ধীর (5x +)
slice(bytes)
তুলনায় দ্রুত slice(string)
- উত্সের স্ট্রিংটি বাইট পরীক্ষার ফলাফল: স্ট্রাক্ট (1x), অপারেটর.ইটমেজেটার (1.7x), প্রাক্পম্পাইল্ড স্লাইসঅবজেক্ট এবং তালিকা অনুধাবন (2.8x), রি.প্যাটেন অবজেক্ট (2.9x)
বড় ফাইলগুলির সাথে কাজ করার সময় আমরা প্রায়শই ব্যবহার করি with open ( file, "rb") as f:
।
পদ্ধতিটি উপরের ফাইলগুলির মধ্যে প্রায় ২.৪ সেকেন্ডকে অনুসরণ করে।
আমি মনে করি উপযুক্ত হ্যান্ডলার, যা 1 মিলিয়ন সারি ডেটা প্রক্রিয়া করে, প্রতিটি সারি 20 টি ক্ষেত্রগুলিতে বিভক্ত হয় এবং 2.4 সেকেন্ডেরও কম সময় নেয়।
আমি কেবল এটি পাই stuct
এবং itemgetter
প্রয়োজনীয়তাগুলি পূরণ করি
PS: সাধারণ প্রদর্শনের জন্য, আমি ইউনিকোড স্ট্রকে বাইটে রূপান্তর করি। আপনি যদি ডাবল-বাইট পরিবেশে থাকেন তবে আপনার এটি করার দরকার নেই।
from itertools import accumulate
from operator import itemgetter
def oprt_parser(sArgs):
sum_arg = tuple(accumulate(abs(i) for i in sArgs))
cuts = tuple(i for i,num in enumerate(sArgs) if num < 0)
ig_Args = tuple(item for i, item in enumerate(zip((0,)+sum_arg,sum_arg)) if i not in cuts)
oprtObj =itemgetter(*[slice(s,e) for s,e in ig_Args])
return oprtObj
lineb = b'abcdefghijklmnopqrstuvwxyz\xb0\xa1\xb2\xbb\xb4\xd3\xb5\xc4\xb6\xee\xb7\xa2\xb8\xf6\xba\xcd0123456789'
line = lineb.decode("GBK")
fieldwidthsU = (13, -13, 4, -4, 5,-5)
fieldwidths = (13, -13, 8, -8, 5,-5)
parse = oprt_parser(fieldwidthsU)
fields = parse(line)
print('Unicode FixedWidth','fields: {}'.format(tuple(map(lambda s: s.encode("GBK"), fields))))
parse = oprt_parser(fieldwidths)
fields = parse(lineb)
print('ASCII FixedWidth','fields: {}'.format(fields))
line = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n'
fieldwidths = (2, -10, 24)
parse = oprt_parser(fieldwidths)
fields = parse(line)
print(f"fields: {fields}")
আউটপুট:
Unicode FixedWidth fields: (b'abcdefghijklm', b'\xb0\xa1\xb2\xbb\xb4\xd3\xb5\xc4', b'01234')
ASCII FixedWidth fields: (b'abcdefghijklm', b'\xb0\xa1\xb2\xbb\xb4\xd3\xb5\xc4', b'01234')
fields: ('AB', 'MNOPQRSTUVWXYZ0123456789')
oprt_parser
4x make_parser
(তালিকা বোঝা + স্লাইস)
গবেষণার সময় দেখা গেল, সিপিইউর গতি যখন দ্রুত হয় তখন মনে হয় যে re
পদ্ধতিটির দক্ষতা দ্রুত বৃদ্ধি পায়।
যেহেতু আমার কাছে পরীক্ষার জন্য আরও বেশি ভাল কম্পিউটার নেই, তাই আমার পরীক্ষার কোড সরবরাহ করুন, যদি কেউ আগ্রহী হন তবে আপনি এটি দ্রুত কম্পিউটারের মাধ্যমে পরীক্ষা করতে পারেন।
রান পরিবেশ:
- OS: win10
- অজগর: 3.7.2
- সিপিইউ: এমডি অ্যাথলন এক্স 3 450
- এইচডি: সিগেট 1 টি
import timeit
import time
import re
from itertools import accumulate
from operator import itemgetter
def eff2(stmt,onlyNum= False,showResult=False):
'''test function'''
if onlyNum:
rl = timeit.repeat(stmt=stmt,repeat=roundI,number=timesI,globals=globals())
avg = sum(rl) / len(rl)
return f"{avg * (10 ** 6)/timesI:0.4f}"
else:
rl = timeit.repeat(stmt=stmt,repeat=10,number=1000,globals=globals())
avg = sum(rl) / len(rl)
print(f"【{stmt}】")
print(f"\tquick avg = {avg * (10 ** 6)/1000:0.4f} s/million")
if showResult:
print(f"\t Result = {eval(stmt)}\n\t timelist = {rl}\n")
else:
print("")
def upDouble(argList,argRate):
return [c*argRate for c in argList]
tbStr = "000000001111000002222真2233333333000000004444444QAZ55555555000000006666666ABC这些事中文字abcdefghijk"
tbBytes = tbStr.encode("GBK")
a20 = (4,4,2,2,2,3,2,2, 2 ,2,8,8,7,3,8,8,7,3, 12 ,11)
a20U = (4,4,2,2,2,3,2,2, 1 ,2,8,8,7,3,8,8,7,3, 6 ,11)
Slng = 800
rateS = Slng // 100
tStr = "".join(upDouble(tbStr , rateS))
tBytes = tStr.encode("GBK")
spltArgs = upDouble( a20 , rateS)
spltArgsU = upDouble( a20U , rateS)
testList = []
timesI = 100000
roundI = 5
print(f"test round = {roundI} timesI = {timesI} sourceLng = {len(tStr)} argFieldCount = {len(spltArgs)}")
print(f"pure str \n{''.ljust(60,'-')}")
def str_parser(sArgs):
def prsr(oStr):
r = []
r_ap = r.append
stt=0
for lng in sArgs:
end = stt + lng
r_ap(oStr[stt:end])
stt = end
return tuple(r)
return prsr
Str_P = str_parser(spltArgsU)
testList.append("Str_P(tStr)")
print(f"pure bytes \n{''.ljust(60,'-')}")
def byte_parser(sArgs):
def prsr(oBytes):
r, stt = [], 0
r_ap = r.append
for lng in sArgs:
end = stt + lng
r_ap(oBytes[stt:end])
stt = end
return r
return prsr
Byte_P = byte_parser(spltArgs)
testList.append("Byte_P(tBytes)")
print(f"re compile object \n{''.ljust(60,'-')}")
def rebc_parser(sArgs,otype="b"):
re_Args = "".join([f"(.{{{n}}})" for n in sArgs])
if otype == "b":
rebc_Args = re.compile(re_Args.encode("GBK"))
else:
rebc_Args = re.compile(re_Args)
def prsr(oBS):
return rebc_Args.match(oBS).groups()
return prsr
Rebc_P = rebc_parser(spltArgs)
testList.append("Rebc_P(tBytes)")
Rebc_Ps = rebc_parser(spltArgsU,"s")
testList.append("Rebc_Ps(tStr)")
print(f"struct \n{''.ljust(60,'-')}")
import struct
def struct_parser(sArgs):
struct_Args = " ".join(map(lambda x: str(x) + "s", sArgs))
def prsr(oBytes):
return struct.unpack(struct_Args, oBytes)
return prsr
Struct_P = struct_parser(spltArgs)
testList.append("Struct_P(tBytes)")
print(f"List Comprehensions + slice \n{''.ljust(60,'-')}")
import itertools
def slice_parser(sArgs):
tl = tuple(itertools.accumulate(sArgs))
slice_Args = tuple(zip((0,)+tl,tl))
def prsr(oBytes):
return [oBytes[s:e] for s, e in slice_Args]
return prsr
Slice_P = slice_parser(spltArgs)
testList.append("Slice_P(tBytes)")
def sliceObj_parser(sArgs):
tl = tuple(itertools.accumulate(sArgs))
tl2 = tuple(zip((0,)+tl,tl))
sliceObj_Args = tuple(slice(s,e) for s,e in tl2)
def prsr(oBytes):
return [oBytes[so] for so in sliceObj_Args]
return prsr
SliceObj_P = sliceObj_parser(spltArgs)
testList.append("SliceObj_P(tBytes)")
SliceObj_Ps = sliceObj_parser(spltArgsU)
testList.append("SliceObj_Ps(tStr)")
print(f"operator.itemgetter + slice object \n{''.ljust(60,'-')}")
def oprt_parser(sArgs):
sum_arg = tuple(accumulate(abs(i) for i in sArgs))
cuts = tuple(i for i,num in enumerate(sArgs) if num < 0)
ig_Args = tuple(item for i,item in enumerate(zip((0,)+sum_arg,sum_arg)) if i not in cuts)
oprtObj =itemgetter(*[slice(s,e) for s,e in ig_Args])
return oprtObj
Oprt_P = oprt_parser(spltArgs)
testList.append("Oprt_P(tBytes)")
Oprt_Ps = oprt_parser(spltArgsU)
testList.append("Oprt_Ps(tStr)")
print("|".join([s.split("(")[0].center(11," ") for s in testList]))
print("|".join(["".center(11,"-") for s in testList]))
print("|".join([eff2(s,True).rjust(11," ") for s in testList]))
আউটপুট:
Test round = 5 timesI = 100000 sourceLng = 744 argFieldCount = 20
...
...
Str_P | Byte_P | Rebc_P | Rebc_Ps | Struct_P | Slice_P | SliceObj_P|SliceObj_Ps| Oprt_P | Oprt_Ps
-----------|-----------|-----------|-----------|-- ---------|-----------|-----------|-----------|---- -------|-----------
9.6315| 7.5952| 4.4187| 5.6867| 1.5123| 5.2915| 4.2673| 5.7121| 2.4713| 3.9051