Это достойный способ обмена динамическими файлами ConfigObj? - PullRequest
0 голосов
/ 18 января 2012

У меня есть несколько процессов Python, которые контролируют и действуют на физический ввод-вывод. Например. выключите двигатель, если ток слишком велик. Они должны сообщить друг другу, почему они что-то сделали, поэтому я подумал, что общий файл может быть простым решением. Различные процессы могут записывать в этот файл, а другие должны знать, когда он был записан. Я уже использую ConfigObj для статических файлов конфигурации, поэтому я решил попробовать его для динамических файлов. Запись не должна происходить очень часто, возможно, не более одной в секунду и обычно намного медленнее, чем это. Я придумал этот пример, который, кажется, работает.

import copy
import os.path
import threading
import time
from configobj import ConfigObj

class config_watcher(threading.Thread):
    def __init__(self,watched_items):
        self.watched_items = watched_items
        self.config = self.watched_items['config'] 
        super(config_watcher,self).__init__()
    def run(self):
        self.reload_config()
        while 1:
            # First look for external changes
            if self.watched_items['mtime'] <> os.path.getmtime(self.config.filename):
                print "external chage detected"
                self.reload_config()
            # Now look for external changes
            if self.watched_items['config'] <> self.watched_items['copy']: 
                print "internal chage detected"
                self.save_config()
            time.sleep(.1)
    def reload_config(self):
        try:
            self.config.reload()
        except Exception:
            pass
        self.watched_items['mtime'] = os.path.getmtime(self.config.filename)
        self.watched_items['copy'] = copy.deepcopy(self.config)
    def save_config(self):
        self.config.write()
        self.reload_config()

if __name__ == '__main__':
    from random import randint
    config_file = 'test.txt'
    openfile = open(config_file, 'w')
    openfile.write('x = 0 # comment\r\n')
    openfile.close()
    config = ConfigObj(config_file)
    watched_config = {'config':config} #Dictionary to pass to thread
    config_watcher = config_watcher(watched_config) #Start thread
    config_watcher.setDaemon(True) # and make it a daemon so we can exit on ctrl-c
    config_watcher.start()
    time.sleep(.1) # Let the daemon get going
    while 1:
        newval = randint(0,9)
        print "is:{0} was:{1}, altering dictionary".format(newval,config['x'])
        config['x'] = newval
        time.sleep(1)
        openfile = open(config.filename, 'w')
        openfile.write('x = {0} # external write\r\n'.format(randint(10,19)))
        openfile.close()
        time.sleep(1)
        print "is {1} was:{0}".format(newval,config['x'])
        time.sleep(1)

У меня вопрос: есть ли лучший / более легкий / чистый способ сделать это?

Ответы [ 2 ]

2 голосов
/ 18 января 2012

Ваш подход уязвим к условиям гонки, если у вас есть несколько процессов, которые пытаются отслеживать и обновлять одни и те же файлы.

Я бы предпочел использовать для этого SQLite, создав таблицу с метками времени для записи сообщений. Поток «monitor» может просто проверить максимальную временную метку или целочисленное значение ключа. Кто-то скажет, что это излишне, я знаю, но я уверен, что как только у вас будет общая база данных в системе, вы найдете для нее и другие умные способы использования.

В качестве бонуса вы получаете возможность аудита; История изменений может быть записана в таблице.

1 голос
/ 24 ноября 2015

Для описанного вами варианта использования, то есть: изоляция и связь нескольких процессов, вы должны серьезно рассмотреть Redis как альтернативу СУБД SQL.

Цитата Офер Бенгал, генеральный директор Redis Labs,

«Redis - это [...] база данных значений ключей и [...] структурированный механизм данных»

Короче говоря,

  • Это очень гибко благодаря общим командам управления данными.
  • Поддерживает транзакции.
  • Это легкий и быстрый.
  • При необходимости вы можете настроить его только для чтения (без записи на диск).
  • Он стабилен и доступен для нескольких вычислительных платформ.

Для получения дополнительной информации о транзакциях Redis вы можете проверить:

...