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()
请注意,在这两种方法中,您都可能会错过最终数据:您必须检查是否有数据等待写入并妥善处理。
我想从传感器获取数据,并以正确的顺序将该记录放在云服务上。
记录需要时间,所以我尝试使用线程方法,这样我可以同时获取数据(否则记录时数据会消失)
这是我的虚拟代码。
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()
请注意,在这两种方法中,您都可能会错过最终数据:您必须检查是否有数据等待写入并妥善处理。