具有复杂类的Python pickle

具有复杂类的Python pickle,python,windows,class,service,pickle,Python,Windows,Class,Service,Pickle,我正在开发一个windows服务来监控来自控制系统的信号。我用两个类(IOSignal和Control)对系统进行了建模。每个控件实例都有一些与之关联的IOSignals实例。当与特定控件关联的所有iosignal都处于特定状态时,我希望服务做些什么。在我的真实代码中,它将在数据库中注册此事件。为了解释我的问题,我为我的原始代码创建了一个非常简化的版本。 问题是,当它作为服务运行时,我希望存储所有控件和IOSignal实例的状态,以便在重新启动服务时,我可以“记住”系统停止时的状态。我是用泡菜做

我正在开发一个windows服务来监控来自控制系统的信号。我用两个类(IOSignal和Control)对系统进行了建模。每个控件实例都有一些与之关联的IOSignals实例。当与特定控件关联的所有iosignal都处于特定状态时,我希望服务做些什么。在我的真实代码中,它将在数据库中注册此事件。为了解释我的问题,我为我的原始代码创建了一个非常简化的版本。 问题是,当它作为服务运行时,我希望存储所有控件和IOSignal实例的状态,以便在重新启动服务时,我可以“记住”系统停止时的状态。我是用泡菜做的。似乎酸洗部分正在工作,因为我可以用另一个脚本打开文件并检索对象的信息。 我的系统的复杂性在于我在每个控制对象中都存储了IOSignals实例,反之亦然。 当我启动该服务时,它似乎工作正常,但当我重新启动它时,我开始收到错误消息,表明重新创建的对象没有某些属性(主要是“d”和“logger”) 我重载了getstaesetstate方法,试图使pickle工作,但我认为我遗漏了一些东西。我遵循了python文档()中给出的说明

下面是我的类的代码(我将它们保存在名为Observer.py的文件中)

下面是创建服务和使用Observer的代码。我称之为teste_service.py 要安装它,请在命令行中键入以下命令“pythonc:\pathtofile\teste\u service.py install”,并将其运行在Windows服务中。 服务的名称是TEST\u Event\u服务

# -*- coding: utf-8 -*-
"""
Created on Thu Jul 27 09:07:29 2017

@author: me
"""

from Observer import IOSignal
from Observer import Control
import os
import threading
import logging
import logging.config
import win32api
import win32service
import win32serviceutil
import win32event
import random
import time
import pickle

class InterruptedException(Exception):
    pass

class WorkerThread(threading.Thread):
    def __init__(self, controller,dCONFIG):
        self._controller = controller
        self._stop = threading.Event()
        super(WorkerThread, self).__init__()

        self.dCONFIG=dCONFIG
        self.dIO=dCONFIG['dIO']
        self.dCTRL=dCONFIG['dCTRL']

        #logger
        self.logger=logging.getLogger('teste.SERVICE')

    def stop(self):
        self._stop.set()

    def stopped(self):
        return self._stop.isSet()

    def saveCACHE(self):
        try:
           f=open(r'C:\TIER3\teste\teste.pkl','wb')
           pickle.dump(self.dCONFIG,f,protocol=4)
           f.close()
        except Exception as e:
           self.logger.error("Error saving cache - ErrMsg -> {}".format(str(e)))

    def getCONFIG(self):
        return self.dCONFIG

    def run(self):
        try:
           # simulater signal state based on a random number generator
           for signal in self.dIO.values():
               r=random.random()
               if r>0.5:
                   signal.UpdateIOSinal('False')
               else:
                   signal.UpdateIOSinal('True')

           #updating dCONFIG to pickle it
           self.dCONFIG['dIO']=self.dIO
           self.dCONFIG['dCTRL']=self.dCTRL

           try:
               self.saveCACHE()
           except Exception as e:
               self.logger.error("Error saving cache - ErrMsg -> {}".format(str(e)))

           #self.logger.info('run finished')
           time.sleep(10)
        except InterruptedException as e:
           # We are forcefully quitting 
           self.logger.error('Interruption Exception - {}'.format(str(e)))
           pass
        except Exception as e:
            self.logger.error('Unexpected Error - {}'.format(str(e)))
            #self.logger.error(e)
            pass
           # Oh oh, did not anticipate this, better report to Windows or log it
        finally:
            #pass
           # Close/release any connections, handles, files etc.
           # OK, we can stop now
            win32event.SetEvent(self._controller)

class test_service(win32serviceutil.ServiceFramework):

   _svc_name_ = "pyTEST"
   _svc_display_name_ = "TEST Event service"
   _svc_description_ = "Service to teste python service"

   def __init__(self, args):
       win32serviceutil.ServiceFramework.__init__(self, args)
       self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)     
       self.hWaitDone = win32event.CreateEvent(None, 0, 0, None)
       self.dCONFIG={}
       #------------------------------------------------------------------------------
       # Creating logger
       #------------------------------------------------------------------------------
       logging.config.fileConfig(r'c:\tier3\teste\teste_logging.conf')
       # create logger
       self.logger = logging.getLogger('teste')

       self.logger.info(self._svc_name_ + " - STARTED!")
       #creating some IOSignals and Controls
       dIO={}
       dCTRL={}
       try:
           if os.path.exists(r'C:\TIER3\teste\teste.pkl'):
               f=open(r'C:\TIER3\teste\teste.pkl','rb')
               self.dCONFIG=pickle.load(f)
               dIO=self.dCONFIG['dIO']
               dCTRL=self.dCONFIG['dCTRL']
               f.close()            
           else:
               dIO[1]=IOSignal('IO1')
               dIO[2]=IOSignal('IO2')
               dIO[3]=IOSignal('IO3')
               dIO[4]=IOSignal('IO4')
               dIO[5]=IOSignal('IO5')
               dIO[6]=IOSignal('IO6')
               dIO[7]=IOSignal('IO7')        
               dIO[8]=IOSignal('IO8')

               dCTRL[1]=Control('CTRL1')
               dCTRL[2]=Control('CTRL2')
               dCTRL[3]=Control('CTRL3')
               dCTRL[4]=Control('CTRL4')

               dIO[1].AppendControl(dCTRL[1])
               dIO[2].AppendControl(dCTRL[1])
               dIO[3].AppendControl(dCTRL[2])
               dIO[4].AppendControl(dCTRL[2])
               dIO[5].AppendControl(dCTRL[3])
               dIO[6].AppendControl(dCTRL[3])
               dIO[7].AppendControl(dCTRL[4])
               dIO[8].AppendControl(dCTRL[4])

               dCTRL[1].register_signal(dIO[1])
               dCTRL[1].register_signal(dIO[2])
               dCTRL[2].register_signal(dIO[3])
               dCTRL[2].register_signal(dIO[4])
               dCTRL[3].register_signal(dIO[5])
               dCTRL[3].register_signal(dIO[6])
               dCTRL[4].register_signal(dIO[7])
               dCTRL[4].register_signal(dIO[8])

               self.dCONFIG={}
               self.dCONFIG['dIO']=dIO
               self.dCONFIG['dCTRL']=dCTRL

       except Exception as e:
           self.logger.error("Error opening teste.pkl - ErrMsg -> {}".format(str(e)))

   def SvcStop(self):
       self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
       win32event.SetEvent(self.hWaitStop)

   def SvcDoRun(self):
        import servicemanager      
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, '')) 

        #create worker 1st run
        self.worker = WorkerThread(self.hWaitDone,self.dCONFIG)
        self.worker.setDaemon=True
        self.worker.start()

        while True:
            rc = win32event.WaitForMultipleObjects([self.hWaitStop, self.hWaitDone],False,win32event.INFINITE)
            #self.logger.debug('rc = {}'.format(rc))
            # Check to see if self.hWaitStop happened as part of Windows Service Management
            if rc == 0:
                # Stop signal encountered
                self.logger.info(self._svc_name_ + " - STOPPED!")
                servicemanager.LogInfoMsg(self._svc_name_ + " - STOPPED!")  #For Event Log
                break
            if rc == 1:
                #create worker
                self.dCONFIG=self.worker.getCONFIG()
                self.worker = WorkerThread(self.hWaitDone,self.dCONFIG)
                self.worker.setDaemon=True
                self.worker.start()

def ctrlHandler(ctrlType):
   return True

if __name__ == '__main__':   
   win32api.SetConsoleCtrlHandler(ctrlHandler, True)   
   win32serviceutil.HandleCommandLine(test_service)
这是日志集

[loggers]
keys=root,teste

[handlers]
keys=logfile,consoleHandler

[formatters]
keys=simpleFormatter,logfileformatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_teste]
level=DEBUG
handlers=logfile
qualname=teste
propagate=0

[formatter_logfileformatter]
format=%(asctime)s %(name)-12s: %(levelname)s %(message)s

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[handler_logfile]
class=handlers.RotatingFileHandler
level=DEBUG
args=(r'C:\tier3\teste\pyteste.log','a',5000000,20)
formatter=logfileformatter
我认为我的问题在于getstatesetstate定义

下面是我收到的错误消息示例

2017-08-02 22:58:00,348 teste.SERVICE: ERROR Error saving cache - ErrMsg -> 'IOSignal' object has no attribute 'd'
2017-08-02 22:58:10,366 teste.SERVICE: ERROR Unexpected Error - 'IOSignal' object has no attribute 'logger'

有人知道我的问题出在哪里吗?

我设法找到了一个并非如我所愿完美的解决方案。由于实例没有被完美地重新创建,我在每次服务运行时创建所有实例,并检查是否有缓存文件。如果有,我将使用缓存中的信息调整实例状态。下面是Observer.py的修改代码。我创建了新的方法来设置所需的值。

我设法找到了一个并非如我所愿完美的解决方案。由于实例没有被完美地重新创建,我在每次服务运行时创建所有实例,并检查是否有缓存文件。如果有,我将使用缓存中的信息调整实例状态。下面是Observer.py的修改代码。我创建了新的方法来设置所需的值。

有很多东西是无法处理的。这可能就是发生的事情。我知道这一点,但如果在python控制台中对文件进行解压,我可以看到类的结构被检索到。我可以调用方法并访问实例属性。但是,在某种程度上,实例重建没有完成,一些项目被遗留下来。更改为
self.\uu dict\uuuuuuuuu.update(d)
。它没有任何效果。您是否检查了它是否有
\uu getstate\uuuuuuu
\uuuuuu setstate\uuuuu
方法?这就是pickle用来保存对象状态的方法。有很多东西是不能被pickle的。这可能就是发生的事情。我知道这一点,但如果在python控制台中对文件进行解压,我可以看到类的结构被检索到。我可以调用方法并访问实例属性。但是,在某种程度上,实例重建没有完成,一些项目被遗留下来。更改为
self.\uu dict\uuuuuuuuu.update(d)
。它没有任何效果。您是否检查了它是否有
\uu getstate\uuuuuuu
\uuuuuu setstate\uuuuu
方法?这就是pickle用来保存对象状态的方法。
2017-08-02 22:58:00,348 teste.SERVICE: ERROR Error saving cache - ErrMsg -> 'IOSignal' object has no attribute 'd'
2017-08-02 22:58:10,366 teste.SERVICE: ERROR Unexpected Error - 'IOSignal' object has no attribute 'logger'