对数组进行迭代的行为就像在迭代期间修改数组一样,但是没有发生这种情况

时间:2017-01-04 23:37:49

标签: python

我正在为python中的气象站编写一些软件。每分钟,每分钟都会从传感器中获取新值(这些值实际上取自每分钟更新的文件)并添加到数组中。此数组中的项目将上载到联机数据库。如果例如因特网连接断开,则阵列充当缓冲器以阻止当前最新数据被新版本覆盖。当连接恢复时,阵列中的项目都可以上传,任何内容都不会丢失。数组的填充发生在一个单独的线程中。

回到主线程,1分钟后,制作一个数组副本。然后迭代该副本并将每个项目上载到数据库。在上传项目之后,它将从ORIGINAL数组中删除,但不会从副本中删除,以防止因操作迭代而导致的错误。如果上传任何项目时发生错误,则整个迭代停止并在下一分钟恢复,以便保留数据库中数据的时间顺序。这是线程安全的,因为我正在从原始数组中删除,但我正在迭代它的副本,我发现代码中任何地方的线程方面都没有问题。

但是,我很难删除看起来像是在迭代时修改列表时会发现的问题,即使这在任何地方都没有发生。当每分钟提供一个数据时(这是正常操作),一切都上传得很好。此外,如果阵列中有两个项目(通过删除一分钟的互联网连接完成),它也可以正常工作。两个项目都按正确的顺序上传。但是,如果列表中上传的项目超过两个(互联网停机时间超过一分钟),则迭代似乎会跳过列表中的其他所有项目。这导致上传所有其他项目,然后上载阵列中剩余项目的每个其他项目,依此类推,直到阵列每分钟返回正常项目。这导致数据库中的上传失序。

我已将错误缩小到从uploadBuffer数组中删除项目的行,因为没有此行它可以正常工作(显然,上传后项目不会从缓冲区中删除)。我没有看到这个问题是如何存在的,因为我正在迭代原始列表的副本。从原始列表中删除项目是使用其值而不是其索引,因此这不是问题。此外,在迭代开始之前,原始数组的副本会生成一次,因此我不会看到从原始数据中删除项目如何影响副本上的迭代。

我真的很想解决这个问题,因为我已经尝试了两周以上没有运气,所以感谢您的帮助,我的代码如下。另外,如果您发现我使用线程锁的方式有任何问题,请提及,因为我不能完全确定我是否正确使用它们。

import urllib2
from lxml import etree
import os
import datetime
import time
import httplib
import socket
import threading

timeFormat = "%d/%m/%Y at %H:%M:%S.%f"
rollingData = "/home/pi/weatherstation/other/latest.xml"
bufferLock = threading.Lock()

print("MOD_UPLOAD: file watching started on " +
      datetime.datetime.now().strftime(timeFormat))
uploadBuffer = []

def watchForReport():
    previousModified = os.stat(rollingData)[8]

    while True:
        try:
            currentModified = os.stat(rollingData)[8]

            # New data needs to be uploaded
            if not currentModified == previousModified:
                newData = open(rollingData, "r").read()

                bufferLock.acquire()
                uploadBuffer.append(newData)
                bufferLock.release()

                previousModified = currentModified

        except:
            print("OSError")

# Watch for new data in separate thread
threading.Thread(target = watchForReport).start()


while True:
    currentSecond = datetime.datetime.now().strftime("%S")

    if currentSecond == "01" or currentSecond == "02":
        if bufferLock.locked() == False:

            bufferLock.acquire()
            bufferCopy = uploadBuffer
            bufferLock.release()

            # If there are records to be uploaded
            if len(bufferCopy) > 0:

                for item in bufferCopy:
                    print("\nreport: " + item[:35])
                    print("bufferCount: " + str(len(bufferCopy)))

                    if item == "":
                        # This isn't the problem, as the text 'empty' is almost never printed
                        print("empty")
                        bufferCopy.remove(item)
                        break
                    else:
                        report = etree.fromstring(item)

                    # Separate date and time and format
                    timestamp = report.xpath("@time")[0]

                    tDate = timestamp.rsplit("T", 2)[0]
                    tTime = timestamp.rsplit("T", 2)[1]
                    tTime = tTime.replace(":", "-")

                    # Generate URL to write data to the database
                    url = "http://www.example.com/uploadfile.php?date="
                    url += tDate + "&time=" + tTime + "&shieldedtemp="
                    url += report.xpath("@shieldedtemp")[0] + "&exposedtemp="
                    url += report.xpath("@exposedtemp")[0] + "&soil10temp="
                    url += report.xpath("@soil10temp")[0] + "&soil30temp="
                    url += report.xpath("@soil30temp")[0] + "&soil100temp="
                    url += report.xpath("@soil100temp")[0]

                    try:
                        # Upload report to database
                        response = urllib2.urlopen(url, timeout = 9).read()
                        print("response: " + response)

                        # Response[4] means success
                        if response == "response[4]":
                            bufferLock.acquire()
                            # Thus is the line causing the problem:
                            uploadBuffer.remove(item)
                            bufferLock.release()

                        else:
                            # Break out of loop on failure to preserve chronology
                            break

                    except urllib2.HTTPError:
                        print("urllib2.HTTPError")
                        print("bufferReCount: " + str(len(bufferCopy)))
                        break

                    except httplib.BadStatusLine:
                        print("httplib.BadStatusLine")
                        print("bufferReCount: " + str(len(bufferCopy)))
                        break

                    except urllib2.URLError:
                        print("urllib2.URLError")
                        print("bufferReCount: " + str(len(bufferCopy)))
                        break

                    except socket.timeout:
                        print("timeout")
                        print("bufferReCount: " + str(len(bufferCopy)))
                        break

                    print("bufferReCount: " + str(len(bufferCopy)))

0 个答案:

没有答案