我正在開發一個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