我正在开发一个Windows服务来监视控制系统的信号。我用两个类(IOSignal和Control)模拟了系统。每个Control实例都有一些与之关联的IOSignals实例。当与特定控件关联的所有IOSignals都处于特定状态时,我希望该服务能够执行某些操作。在我的真实代码中,它将在数据库中注册这个事件。为了解释我的问题,我创建了一个非常简化的版本,我的原始代码。 问题是,当它作为服务运行时,我想存储所有Control和IOSignal实例的状态,因此当我重新启动服务时,我可以“记住”系统停止时的状态。我正在使用泡菜来做到这一点。似乎酸洗部分正在工作,显然我可以在另一个脚本中打开文件并检索我的对象的信息。 我系统的复杂性在于,我在每个Control对象中都存储了IOSignals实例,反之亦然。 当我明星的服务似乎工作正常,但当我重新启动它,我开始接收错误消息,重新创建的对象没有一些属性(主要是'd'和'记录器') 我有覆盖getstae和setstate尝试做酸菜的方法,但我认为我错过了一些东西。我跟着这条巨蟒文档中给出的说明(https://docs.python.org/2.0/lib/pickle-example.html)复杂类Python腌菜
这里是我的类的代码(我将它们保存在一个名为Observer.py文件)
# -*- coding: utf-8 -*-
"""
Created on Wed Aug 2 11:07:28 2017
@author: me
"""
from logging import getLogger
#import logging
class IOSignal(object):
def __init__(self,tag,val='True'):
self.tag=tag
self.value=val
self.CONTROLS=[]
#logger
self.logger=getLogger('teste.IOSignals')
# dict to serialize
self.d={}
self.d['tag']=self.tag
self.d['value']=self.value
self.d['CONTROLS']=self.CONTROLS
def getTag(self):
return self.tag
def getValue(self):
return self.value
def UpdateIOSinal(self,val):
self.value=val
try:
for control in self.CONTROLS:
#self.logger.debug('updating controls')
control.update()
except Exception as e:
self.logger.error("Error updating signal - ErrMsg -> {}".format(str(e)))
def AppendControl(self,control):
self.CONTROLS.append(control)
def UpdateControls(self):
for control in self.CONTROLS:
control.update()
def __getstate__(self):
return self.d
def __setstate__(self, d):
self.tag=d['tag']
self.value=d['value']
self.CONTROLS=d['CONTROLS']
self.__dict__= d
class Control(object):
def __init__(self,tag,state=False):
self.tag=tag
self.state=state
self.IOSignals={}
#logger
self.logger=getLogger('teste.CONTROLS')
# dict to serialize
self.d={}
self.d['tag']=self.tag
self.d['state']=self.state
self.d['IOSignals']=self.IOSignals
def getTag(self):
return self.tag
def getState(self):
return self.state
def register_signal(self,signal):
self.IOSignals[len(self.IOSignals)]=signal
def update(self):
try:
I=len([e.value for e in self.IOSignals.values() if e.value=='False'])
if I==len(self.IOSignals):
self.logger.info("Control {} actuated".format(self.tag))
except Exception as e:
self.logger.error("Error updating Contro - ErrMsg -> {}".format(str(e)))
def __getstate__(self):
return self.d
def __setstate__(self, d):
self.tag=d['tag']
self.state=d['state']
self.IOSignals=d['IOSignals']
self.__dict__= d
,这里是创建代码服务和使用Observer。我把它叫做teste_service.py 来安装它,在命令行中输入以下命令“python c:\ pathtofile \ teste_service.py install”,并将它放在Windows服务中运行。 服务的名称是TEST_Event_Service。
# -*- 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
我认为我的问题是在,有getstate和setstate这定义。
这里是我收到的错误消息的示例。
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'
任何人都有一些ideia我的问题在哪里?
有很多事情不能被腌制。这可能是发生了什么 – Zizouz212
是的。我知道,但如果在python控制台中取消选中文件,我可以看到类的结构被检索到。我可以调用方法并访问实例属性。但是,在某种程度上,重构实例并不完整,有些项目被抛在后面。 – Dariva
更改为'self .__ dict __。update(d)'。 – stovfl