代码之家  ›  专栏  ›  技术社区  ›  Shawn H.

使多线程执行单个命令

  •  0
  • Shawn H.  · 技术社区  · 7 年前

    为了安全起见,我正在编写一个创建虚拟文件的小脚本,用于填充磁盘(通常是usb密钥)。

    实际上,我使用线程模块,即使我知道如何使用它,我仍然在努力解决一些问题。

    下面是一些介绍我的问题的代码。

    import sys
    
    if sys.version_info[0] >= 3: # Check Python's version, and dismiss Python 3
        raise Exception('You must use Python 2 to launch this program')
    
    from threading import Thread
    
    index, running = 0, True
    
    def main():
        multiThreading()
    
    def multiThreading():
        thread1 = Thread(target=fill) # Both threads targets fill()
        thread1.daemon = True
        thread1.start()
    
        thread2 = Thread(target=fill)
        thread2.daemon = True
        thread2.start()
    
        while running: # Without this infinite loop, the program exits while the threads are still on, which is not really a problem in this bit of code, 
        # as they finish their tasks, but it is one in the original script. Anyway.
            if running is False:
                return None
    
    def fill(): # this function  normally fills a chosen drive with data
        global index
        global running
        while running:
            index += 1
            print index
            if index >= 10:
                running = False
                # The index is used AFTER index += 1 is executed, which causes a problem
    
    
    if __name__ == '__main__':
        main()
    
    print 'End'
    

    它返回

    12
    
    34
    
    56
    
    78
    
    910
    
    End
    >>> 
    

    事实上,我想把它打印出来

    1
    
    2
    
    3
    
    ...
    
    10
    
    End
    >>>
    

    但是两个线程都通过了索引,索引将2而不是1相加(2,因为当然有两个线程)

    我尝试了看门狗和其他功能,但结果是一样的。 而且,一次性看门狗也不是解决方案,因为我想根据需要多次循环。

    预测问题:为什么要使用多线程?因为它使文件创建速度更快。

    你有解决办法吗?非常感谢您的阅读!

    PS:请原谅我的一些英语错误,不是我的母语:p;如果你对标题有更好的想法,我洗耳恭听

    1 回复  |  直到 7 年前
        1
  •  0
  •   u354356007    7 年前

    发生这种情况的原因是,当多个线程写入流(stdout或文件)时,它们的输出几乎肯定会混合并产生无法读取的结果。您至少可以获得部分有序的输出,这主要是因为python有GIL。(顺便说一句,我得到了不同的输出。)一般情况下,当未指定语言时,没有任何东西可以阻止OS以以下方式调度线程执行:

    index += 1  # Thread 1
    index += 1  # Thread 2
    print index # Thread 2
    index += 1  # Thread 2 (next iteration)
    print index # Thread 1
    

    因此,一般来说,当您向共享变量写入*时,需要使用互斥体、信号量或其他同步原语来保护这部分代码,以确保线程可以执行整个 临界截面,临界截面 不被打断:

    from threading import Thread, Lock
    
    index_operations_lock = Lock()
    
    def mutlithreading():
        # all the stuff you already have
        thread1.join()
        thread2.join()
    
    def fill():
        global index
        global running
        while running:
            with index_operations_lock:
                if index >= 10:
                    running = False
                    return
                index += 1
                print index
    

    保护您有争议的资源。另外,请注意,这种方法并没有指定线程执行的顺序。如果您需要先从线程1写入,然后再从线程2写入,那么您将需要再执行两个锁还是实现生产者-消费者模式(即,让两个线程在队列中写入,让第三个线程从队列中读取并写入文件/标准输出)。


    *-在python中,赋值 a = b 也是一个写操作,因为这会增加由引用的对象中的引用计数器 b .