Python, Büyük Dosya, Hız Sorunu

Başlatan muhittin_kaplan, 08 Nisan 2017, 08:40:16

muhittin_kaplan

1.000.000 kadar kayıt barındıran bir dosyayı (binary) parse edip başka bir dosyaya yazmam gerekiyor (ortalama 40bytelık seriler) dolayısıyla bu işlemi hızlandırmam lazım.
İşin özünden bahsedeyim biraz; bu dosyada belli bir header var ve bu header in içinde verinin uzunluğu mevcut (b'\x3C' yada b'\x2A' gibi). bu veri uzunluğuna göre alıp gereklei yerleri kdiğer dosyaya atmam lazım ki bu uzunluk verisi karmaşık bir yapıda. (bazen ardarda 30 adet 3C gelirken arada 2A uzunluğundada geliyor). Sonuçta bir iteraktif yapı ile yapıyorum.
Headeri oku, uzunlukbilgisini al, uzunluk kadar oku,gerekli çevrimleri yap, verileri yeni dosyaya yaz,Sonraki header i oku....
Görüş ve önerilerinize açığım.

ErsinErce

#1
kayıt başlangıç ve uzunluklarını indexleyen bir yapı oluşturup sonra translation işlemini gerçekleştirecek onlarca instance thread oluşturulabilir.
ayrıca raw veriyi komple ram'e çekip ram üzerinden işlemleri yapın, direk dosya üzerinden çalışmayın.

muhittin_kaplan

#2
Hocam Iteratif yapım aşağıdaki gibi.

self.f = open('c:\Record.dat', "rb")
self.okunanDosya = self.f.read()
StartAdress = 0
        while self.Z <= self.DosyaUzunlugu:  
            self.StartAdress = self.okunanDosya.find(b'\x00\x00\x00<', self.Z, self.DosyaUzunlugu)  # 00 00 00 3c
            self.f.seek(self.StartAdress)  # startadresten başla
            TM = self.f.read(self.MesajBoyutu)  # mesaj boyutu kadar al.
            Geo = (TM[34:38])
            Ofset = TM[11]  # Kayit Bulunan Ofset Kodudur
            if Ofset == 0:
                 print("--" * 50, "HATA")
            
işlemler.........
işlemler.........
işlemler.........

            Geo = [""]
            Ofset = 0
            self.Z = self.StartAdress + self.MesajBoyutu
            self.i = self.i + 1

ErsinErce

http://stackoverflow.com/questions/11159077/python-load-2gb-of-text-file-to-memory
https://www.tutorialspoint.com/python/python_multithreading.htm (burada işlem yapılması için sırada bekletiliyor bunun yerine çıkış vermek için sırada bekletmeniz hızı daha da arttırır)


Yapacağınız işlem


dosyayı RAM'e yükle,
ilk Header'ı oku işlenecek verinin başlangıç adresini index[0][0]'a yaz, uzunluk bilgisini al index[0][1]'e yaz,
işlenecek verinin başlangıç adresini index[1][0]'a yaz, uzunluk bilgisini al index[1][1]'e yaz,
...
Index içeriği bitene kadar işleyecek aralarında eş yük dağılımı sağlanacak çekirdek sayısı kadar dönüşüm işlemini yapacak thread oluştur.
threadler bitti mi diye kontrol et.
Threadlerin çıktısını RAM'e yapıp çıktıyı tek seferde dosyaya yazabilirsiniz.




umarım daha açık olmuştur.

engerex

C/C++, Pascal/Delphi, Basic/VB gibi native kod üreten yazılımları neden kullanmıyorsunuz?

muhittin_kaplan

Hocam dosyayi bolemedigimden (bir mesajin ortasina denk gelebilir) thread, multiprocess kullanamadim. (Ama bu konuda calismaya devam ediyorum)


Native kod a gelince hocam, hem linux hem winde calisan bir uygulamaya ihtiyacim var. Onun icin pythonda yapmaya karar verdim. Ayrica matplotlib, basemap, gdal gibi birkac modulle hesaplar yaptiriyorum.


Suan 32mb dosyadan veriler secilip 600 000 kayit ile 30mb dosyaya yazma yaklasik 25saniye tutuyor.

boreas

Header'da hiçbir şablon yok mu sadece başlangıçta ya da bitiş de kullanılan bir karakter ?

muhittin_kaplan

#7
hocam headerda şablon mevcut,
b'\x53\x63\x54\x69\x6d\x65\x32\x3d\x31\x34\x0A ile veriler başlıyor.
\x00\x00\x00\x3C ile bir çeşit
\x00\x00\x00\x2A ile diğeri başlıyor(3c ve 2A uzunluk)  ama arada epeyce boş alanda var. Yani atıyorum 300 kez bu veriler geliyor sonra 00 devam ediyor epey bir müddet sonra veri tekrar başlıyor.

def Basla(self):

    dosya = self.f.read()
    dosyaUzunlugu = dosya.__len__()
    print(dosyaUzunlugu)

    baslangic = b'\x53\x63\x54\x69\x6d\x65\x32\x3d\x31\x34\x0A'
    mesaj3C = b'\x00\x00\x00\x3C'
    mesaj2A = b'\x00\x00\x00\x2A'

    baslangicAdresi = 0

    baslangicAdresi = (dosya.find(baslangic)) + 11
    i = 0

    try:
        while baslangicAdresi<dosyaUzunlugu:
            Mesaj=dosya[baslangicAdresi:baslangicAdresi+4]#aranan bilgi 4byte
            if (Mesaj==mesaj2A):
                #print("2A mesaj kopyalanıyor")
                MSG2A=dosya[baslangicAdresi:baslangicAdresi+42]
                #print(MSG2A)
                baslangicAdresi=baslangicAdresi+42
                self.veri.write(MSG2A)
                i += 1


            elif (Mesaj==mesaj3C):
                #print("3C mesaj kopyalanıyor")
                MSG3C=dosya[baslangicAdresi:baslangicAdresi+60]
                #print(MSG3C)
                baslangicAdresi=baslangicAdresi+60
                self.veri.write(MSG3C)
                i +=1


            else:
                baslangicAdresi=baslangicAdresi+1
        self.veri.close()


şeklinde yaptım şu anda. Çalışmalarım devam ediyor konu üzerinde.

boreas

Hızlı arama algoritmaları vardı büyük verileri ortadan böler vs. Benim aklıma gelen yöntem şu olur dosya 3 ya da 4 e bölünür hepsi başlar başlanıç headerını aramaya. Bulduğu noktada, bulduğu pozisyon kendi başlangıcı ilerlediği kısım kendinden öncekinin bitişi olur. Header pozisyonları bulununca kopyalama işlemi başlanabilir.  Hattaki yapılabiliniyorsa dosya yapısının önüne ya da ek bir dosya olarak index. dosyası oluşturulup aramada iptal edilerek direk o dosya kullanılabilir. Esneklik yapınızı bilmiyorum tabi ki .