python threading 执行顺序不正确,如何修改?

The executing order gets incorrect in python threading, how to make it correct?

我想从传感器获取数据,并以正确的顺序将该记录放在云服务上。

记录需要时间,所以我尝试使用线程方法,这样我可以同时获取数据(否则记录时数据会消失)

这是我的虚拟代码。

import threading
import time

def putrecord(data_put):
    time.sleep(0.8) #it takes time to put record
    print(data_put[-1]) #sometimes unordered (ex. 9,29,19,...)

def main():
    data_put=[]
    for i in range(100):
        time.sleep(0.08) #getting data from a sensor
        data_put.append(i)
        if len(data_put)>=10: #every 10 records
            sub = threading.Thread(target=putrecord,args=(data_put,))
            sub.start()
            data_put=[]
    

if __name__ == '__main__':
    main()

然后不知何故,有时顺序变得不正确(它不会发生在虚拟代码上)。 我不确定为什么会发生这种情况,但我猜它发生在 getting/putting 数据花费的时间比平时长的时候。 在这种情况下,有什么办法可以让记录的顺序正确吗?

我希望让自己被理解。

如果线程“放置记录”的时间过长,您获取和放置数据的方式可能会失败。如果花费的时间足够长,新数据将到达,并且将创建并启动一个新线程。此线程将与旧线程同时“放置”记录,从而导致数据乱序。

此外,您并没有加入您创建的线程。这会导致非常小的资源泄漏(相当于不关闭文件),这可能无关紧要(除非你的程序连续运行多年)。

正如@jarmod 在评论中提出的那样,实现所需内容的最优雅方式是使用队列。不过,您可以使用更简单的方法重用您的代码。

如果您需要在固定数量的记录块中处理数据(如您的示例),您可以将这些块保存在列表中并仅在前一个完成后才启动线程:

import threading
import time

def putrecord(chunk):
    time.sleep(0.8) #it takes time to put record
    for data_put in chunk:
        print(data_put[-1])

def main():
    data=[]
    chunks = []
    sub = None
    for i in range(100):
        time.sleep(0.08) #getting data from a sensor
        data.append(i)
        if len(data) >= 10: #every 10 records
            chunks.append(data)
            data = []
            if sub and  not sub.is_alive():
                sub.join(0)
                sub = None
            if not sub:
                sub = threading.Thread(target=putrecord,args=(chunks,))
                sub.start()
                chunks = []
    if sub:
        sub.join()

if __name__ == '__main__':
    main()

如果您实际上不需要分块处理数据,则可以提供自上一个线程启动以来从传感器获得的任何数据:

import threading
import time

def putrecord(data_put):
    time.sleep(0.8) #it takes time to put record
    print(data_put, data_put[-1]) #sometimes unordered (ex. 9,29,19,...)

def main():
    data_put=[]
    # sub = threading.Thread(target=putrecord,args=(data_put,))
    sub = None
    for i in range(100):
        time.sleep(0.01) #getting data from a sensor
        data_put.append(i)
        if len(data_put) >= 10: #every 10 records
            if sub and  not sub.is_alive():
                sub.join(0)
                sub = None
            if not sub:
                sub = threading.Thread(target=putrecord,args=(data_put,))
                sub.start()
                data_put=[]
    if sub:
        sub.join()

if __name__ == '__main__':
    main()

请注意,在这两种方法中,您都可能会错过最终数据:您必须检查是否有数据等待写入并妥善处理。