2012-08-16 15 views
14

मैं एक ऐप लिख रहा हूं जो एकाधिक थ्रेड से एक ही फ़ाइल में लाइनों को जोड़ता है।पायथन - एकाधिक थ्रेड से एक ही फ़ाइल में संलग्न

मुझे एक समस्या है जिसमें कुछ लाइनें बिना किसी नई लाइन के संलग्न की जाती हैं।

इसके लिए कोई समाधान?

class PathThread(threading.Thread): 
    def __init__(self, queue): 
     threading.Thread.__init__(self) 
     self.queue = queue 

    def printfiles(self, p): 
     for path, dirs, files in os.walk(p): 
      for f in files: 
       print(f, file=output) 

    def run(self): 
     while True: 
      path = self.queue.get() 
      self.printfiles(path) 
      self.queue.task_done() 


pathqueue = Queue.Queue() 
paths = getThisFromSomeWhere() 

output = codecs.open('file', 'a') 

# spawn threads 
for i in range(0, 5): 
    t = PathThread(pathqueue) 
    t.setDaemon(True) 
    t.start() 

# add paths to queue 
for path in paths: 
    pathqueue.put(path) 

# wait for queue to get empty 
pathqueue.join() 
+3

पोस्ट कुछ कोड, कि मदद मिलेगी। –

+2

एक नई लाइन संलग्न करें। – Kuf

+1

* impossibru * की तरह लगता है। – plaes

उत्तर

22

समाधान केवल एक थ्रेड में फ़ाइल को लिखना है।

import Queue # or queue in Python 3 
import threading 

class PrintThread(threading.Thread): 
    def __init__(self, queue): 
     threading.Thread.__init__(self) 
     self.queue = queue 

    def printfiles(self, p): 
     for path, dirs, files in os.walk(p): 
      for f in files: 
       print(f, file=output) 

    def run(self): 
     while True: 
      result = self.queue.get() 
      self.printfiles(result) 
      self.queue.task_done() 

class ProcessThread(threading.Thread): 
    def __init__(self, in_queue, out_queue): 
     threading.Thread.__init__(self) 
     self.in_queue = in_queue 
     self.out_queue = out_queue 

    def run(self): 
     while True: 
      path = self.in_queue.get() 
      result = self.process(path) 
      self.out_queue.put(result) 
      self.in_queue.task_done() 

    def process(self, path): 
     # Do the processing job here 

pathqueue = Queue.Queue() 
resultqueue = Queue.Queue() 
paths = getThisFromSomeWhere() 

output = codecs.open('file', 'a') 

# spawn threads to process 
for i in range(0, 5): 
    t = ProcessThread(pathqueue, resultqueue) 
    t.setDaemon(True) 
    t.start() 

# spawn threads to print 
t = PrintThread(resultqueue) 
t.setDaemon(True) 
t.start() 

# add paths to queue 
for path in paths: 
    pathqueue.put(path) 

# wait for queue to get empty 
pathqueue.join() 
resultqueue.join() 
+0

प्रोसेस थ्रेड में, लाइन - परिणाम = self.process (पथ) ? आप वहां प्रक्रिया() विधि को हाइव नहीं करते हैं .. – user1251654

+0

आपको लगता है कि आप जो चाहते हैं उसे करने के लिए प्रक्रिया विधि को परिभाषित करना है। मैं बस इसे स्पष्ट करने के लिए कोड में संशोधित करता हूं। – Dikei

+0

सही, मेरा बुरा। धन्यवाद। यह बहुत मदद करता है। – user1251654

0

और शायद कुछ और न्यूलाइन जहां वे नहीं होनी चाहिए? आपको इस तथ्य को ध्यान में रखना चाहिए कि किसी साझा संसाधन को एक समय में एक से अधिक धागे तक नहीं पहुंचाया जाना चाहिए या अन्यथा अप्रत्याशित परिणाम हो सकते हैं। (इसे थ्रेड का उपयोग करते समय 'परमाणु संचालन' का उपयोग करने के लिए कहा जाता है) थोड़ा सा अंतर्ज्ञान के लिए इस पृष्ठ पर एक नज़र डालें।
Thread-Synchronization

1

तथ्य यह है कि आप एक ही पंक्ति या एक लाइन के बीच में नई लाइनों पर गड़बड़ पाठ को देखने कभी नहीं एक सुराग कि आप वास्तव में फाइल करने के लिए जोड़कर syncronize करने के लिए की आवश्यकता नहीं है है। समस्या यह है कि आप एक फ़ाइल संभाल को लिखने के लिए प्रिंट का उपयोग करते हैं। मुझे संदेह है कि print वास्तव में एक कॉल में फ़ाइल हैंडल में 2 ऑपरेशन कर रहा है और वे ऑपरेशन थ्रेड के बीच रेसिंग कर रहे हैं।

file_handle.write('whatever_text_you_pass_it') 
file_handle.write(os.linesep) 

और क्योंकि अलग धागे एक ही फाइल संभाल पर एक साथ यह कर रहे हैं कभी कभी एक थ्रेड पहले लिखने में मिल जाएगा और अन्य धागा तो फिर अपनी पहली लिखने में मिलता है और आप होगा: मूल रूप से print की तरह कुछ कर रही है एक पंक्ति में दो कैरिज रिटर्न मिलेगा। या वास्तव में इनमें से कोई क्रमपरिवर्तन।

print का उपयोग करना बंद करने के लिए सबसे आसान तरीका है और केवल write का उपयोग करें। इस तरह कुछ कोशिश करें:

output.write(f + os.linesep) 

यह अभी भी मेरे लिए खतरनाक प्रतीत होता है। मुझे यकीन नहीं है कि आप एक ही फ़ाइल हैंडल ऑब्जेक्ट का उपयोग करके सभी थ्रेडों के साथ क्या उम्मीद कर सकते हैं और इसके आंतरिक बफर के लिए दंडित कर सकते हैं। व्यक्तिगत आईडी पक्ष पूरे मुद्दे को हल करता है और बस प्रत्येक थ्रेड को अपना फ़ाइल संभाल लेता है। यह भी ध्यान रखें कि यह काम करता है क्योंकि लिखने वाले बफर फ्लश के लिए डिफ़ॉल्ट लाइन-बफर किया जाता है, इसलिए जब यह फ़ाइल में फ्लश करता है तो यह os.linesep पर समाप्त होता है। लाइन-बफर्ड का उपयोग करने के लिए इसे मजबूर करने के लिए को open के तीसरे तर्क के रूप में भेजें। आप इस तरह से इसे बाहर का परीक्षण कर सकते हैं:

#!/usr/bin/env python 
import os 
import sys 
import threading 

def hello(file_name, message, count): 
    with open(file_name, 'a', 1) as f: 
    for i in range(0, count): 
     f.write(message + os.linesep) 

if __name__ == '__main__': 
    #start a file 
    with open('some.txt', 'w') as f: 
    f.write('this is the beginning' + os.linesep) 
    #make 10 threads write a million lines to the same file at the same time 
    threads = [] 
    for i in range(0, 10): 
    threads.append(threading.Thread(target=hello, args=('some.txt', 'hey im thread %d' % i, 1000000))) 
    threads[-1].start() 
    for t in threads: 
    t.join() 
    #check what the heck the file had 
    uniq_lines = set() 
    with open('some.txt', 'r') as f: 
    for l in f: 
     uniq_lines.add(l) 
    for u in uniq_lines: 
    sys.stdout.write(u) 

उत्पादन इस तरह दिखता है:

hey im thread 6 
hey im thread 7 
hey im thread 9 
hey im thread 8 
hey im thread 3 
this is the beginning 
hey im thread 5 
hey im thread 4 
hey im thread 1 
hey im thread 0 
hey im thread 2 
संबंधित मुद्दे