【问题标题】:python file writing in threads not writing all linespython文件在线程中写入而不是写入所有行
【发布时间】:2015-02-09 13:36:19
【问题描述】:

我测试了我的代码输出并对其进行了排序,但我没有预期的 0-1999,缺少行。我的代码线程不安全吗?请建议如何在我的代码中添加线程锁,我发现我的 except all 没有抛出任何错误,对吗?谢谢

import time, threading, random

class MyThreadWithArgs(threading.Thread):
    def __init__(self, string):
        threading.Thread.__init__(self)
        self.string = string

    def run(self):
        try:
            fo = open("foo.np2", "a")
            fo.write( self.string )
            fo.write( '\n' )
            time.sleep(random.uniform(0.1, 0.9))
            fo.close()
        except:
            print ("error logging " + self.string)

ttl_threads = 2000
for i in range(ttl_threads):
    t = MyThreadWithArgs(string = str(i))
    t.start()

【问题讨论】:

  • except all 在 Python 中没有任何特殊意义,如果必须进入 except 块,解释器会卡住它。要捕获所有异常,请使用普通的except
  • 这是您的实际代码吗? ttl_threads = 2000 for i in range(ttl_threads): 在我看来不是有效的语法。
  • @Kevin 分开两行,固定
  • 使用with open(...) as... 打开文件。如果您的 try 块中有错误,fo 将不会被关闭。
  • 当我运行你的代码时,我得到一个“打开的文件太多”的异常。也许您可以在主线程中打开文件一次,这样您的其他数千个线程就不必自己做。

标签: python multithreading


【解决方案1】:

这可能会按预期工作。为简单起见,移除了异常处理。

import time, threading, random

class MyThreadWithArgs(threading.Thread):
    def __init__(self, string):
        threading.Thread.__init__(self)
        self.string = string

    def run(self):
        fo.write( self.string + '\n' )
        time.sleep(random.uniform(0.1, 0.9))

fo = open("foo.np2", "a")
ttl_threads = 2000
for i in range(ttl_threads):
    t = MyThreadWithArgs(string = str(i))
    t.start()

在原始程序中,您以追加模式打开同一个文件的多个句柄。每个句柄都维护自己的指向它认为是文件末尾的指针,但线程 0 可以在线程 1 开始写入之前修改文件。 thread-1 在调用 open 时仍会写入文件结尾 WAS 的位置。

通过只保持一个文件描述符打开,您只有一个文件结束指针,并且底层write 系统调用可能通过操作系统内部锁定机制在给定文件描述符上可重入。

我所做的另一项更改是将两个调用中的字符串连接到 write(),因为作为两个单独的调用,您为调度提供了在系统调用之间切换线程的机会,并且可能以两个 @ 结束987654324@ 值在一行中,后跟两个或更多\n 字符串在一行中。

我不知道 python 对write 做出了什么(如果有的话)保证,我只是想知道<unistd.h> write() 在大多数POSIX 平台上如何在C 中工作。如果您需要保证,请查看 python 文档,或者用锁包围 write() 调用。

【讨论】:

  • 布莱恩,很好的答案。比我可以说得更好。快速提问——为了论证类型的事情。您使文件处理一个全局变量(有效地)。您是否还可以将文件句柄传递给构造函数?或者这个伪(或实际上)会克隆引用吗?
  • 是的,您应该能够将文件描述符传递给构造函数。
【解决方案2】:
import time, sys, threading, random

class MyThreadWithArgs(threading.Thread):
    def __init__(self, i, global_msg_i):
        threading.Thread.__init__(self)
        self.i = i
        self.global_msg_i = global_msg_i
    def run(self):
        global global_msg
        try:
            i = self.i
            global_msg_i = self.global_msg_i
            time.sleep(random.uniform(0.1, 0.9))
            print (i)
            global_msg[global_msg_i] = str(i)
            time.sleep(random.uniform(0.1, 0.9))
        except:
            pass
        finally:
            pass

def reset_threads_global_msg():
    global threads, global_msg, global_msg_i, ttl_threads
    threads = []
    global_msg = [None] * ttl_threads
    global_msg_i = 0

def start_join_threads_write_global_msg():
    global threads, global_msg
    for x in threads:
        x.start()
        time.sleep(0.001) # avoid thread create error when creating too fast?!
    [x.join() for x in threads]
    fo = open("foo_test.np++", "a")
    for msg in global_msg:
        if msg is not None:
            fo.write( msg + '\n')
    fo.close()

ttl_threads = 200
reset_threads_global_msg()
for ttl_threads_i in range(1, ttl_threads + 1):
    t = MyThreadWithArgs(i = ttl_threads_i, global_msg_i = global_msg_i)
    threads.append(t)
    global_msg_i += 1
start_join_threads_write_global_msg()
reset_threads_global_msg()

【讨论】:

    猜你喜欢
    • 2014-12-19
    • 2020-08-16
    • 1970-01-01
    • 2017-04-22
    • 1970-01-01
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多