2012-08-16 44 views
14

Tôi đang viết một ứng dụng nối thêm các dòng vào cùng một tệp từ nhiều luồng.python - nối vào cùng một tệp từ nhiều chủ đề

Tôi gặp sự cố trong đó một số dòng được nối vào mà không có dòng mới.

Bất kỳ giải pháp nào cho điều này?

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

bài viết một số mã, mà có thể giúp. –

+2

nối thêm một dòng mới. – Kuf

+1

Âm thanh như * impossibru *. – plaes

Trả lời

22

Giải pháp là chỉ ghi vào tệp trong một chuỗi.

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

trong ProcessThread, dòng - result = self.process (đường dẫn) ? bạn không có phương thức hive() ở đó .. – user1251654

+0

Bạn giả sử để xác định phương thức quy trình để thực hiện những gì bạn muốn. Tôi chỉ sửa đổi mã để làm rõ điều này. – Dikei

+0

đúng, xấu của tôi. cảm ơn. cái này giúp rất nhiều. – user1251654

0

Và có thể một số dòng mới khác không được ở đâu? bạn nên nhớ rằng một tài nguyên được chia sẻ không được truy cập bởi nhiều hơn một luồng tại một thời điểm hoặc các hậu quả không thể đoán trước có thể xảy ra. (nó được gọi là sử dụng 'hoạt động nguyên tử' trong khi sử dụng đề tài) Hãy xem trang này để biết một chút trực giác.
Thread-Synchronization

1

thực tế là bạn không bao giờ nhìn thấy văn bản lộn xộn trên cùng một dòng hoặc dòng mới ở giữa của một dòng là một đầu mối mà bạn thực sự không cần phải bộ hóa phụ thêm vào tập tin. vấn đề là bạn sử dụng in để ghi vào một tập tin đơn. tôi nghi ngờ print thực sự đang thực hiện 2 thao tác để xử lý tệp trong một cuộc gọi và các hoạt động đó đang chạy đua giữa các chuỗi. về cơ bản print đang làm một cái gì đó như:

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

và vì chủ đề khác nhau đang làm điều này cùng một lúc trên tay cầm cùng một tập tin đôi khi một thread sẽ nhận được trong ghi đầu tiên và các chủ đề khác sau đó sẽ nhận được trong ghi đầu tiên và sau đó bạn sẽ nhận được hai trở về vận chuyển trong một hàng. hoặc thực sự bất kỳ hoán vị nào trong số này.

cách đơn giản nhất để giải quyết vấn đề này là ngừng sử dụng print và chỉ sử dụng trực tiếp write. hãy thử một cái gì đó như thế này:

output.write(f + os.linesep) 

điều này vẫn có vẻ nguy hiểm đối với tôi. im không chắc chắn những gì gaurantees bạn có thể mong đợi với tất cả các chủ đề bằng cách sử dụng cùng một đối tượng xử lý tập tin và contending cho bộ đệm nội bộ của nó. cá nhân id bên bước toàn bộ vấn đề và chỉ có mỗi thread có được xử lý tập tin riêng của mình. cũng lưu ý rằng điều này làm việc vì mặc định cho xóa bộ đệm flushes là dòng đệm, do đó, khi nó làm một tuôn ra vào tập tin nó kết thúc trên một os.linesep. để buộc nó sử dụng bộ đệm dòng, hãy gửi một số 1 làm đối số thứ ba của open. bạn có thể kiểm tra nó ra như thế này:

#!/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) 

Kết quả trông như thế này:

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 
Các vấn đề liên quan