2

我每 30 分钟同时从 crontab 运行 2 个 python 脚本,例如

00,30 6-19 * * 0-5 /.../x.py site1
*/3 6-19 * * 0-5 /.../y.py site2

一开始,这两个脚本都导入了一个模块,该模块将一些数据打印到日志中,例如

name = os.path.basename(sys.argv[0])
site = sys.argv[1]
pid = os.getpid()

有时(!)第二个脚本 y 打印到脚本 x 的日志输入参数:name = x 和 site = site1 打印的进程的 PID 不一样。为什么会发生这种情况,我该如何避免这种情况?

PS我怀疑问题与我使用的记录器有关。脚本可以使用在另一个脚本中创建的记录器吗?在这种情况下,它将打印与第一个脚本相关的每一行数据。每个脚本执行相同的代码:

log = logging.getLogger('MyLog')
    log.setLevel(logging.INFO)
    dh = RotatingSqliteHandler(os.path.join(progDirs['log'],'sqlitelog'),processMeta, 5000000)
    log.addHandler(dh)

记录器处理程序定义如下:

class RotatingSqliteHandler(logging.Handler):
   def __init__(self, filename, progData, maxBytes=0):
       logging.Handler.__init__(self)
       self.user = progData['user']
       self.host = progData['host']
       self.progName = progData['name']
       self.site = progData['site']
       self.pid = random.getrandbits(50)
    .....

在日志中,我看到记录器在最后一行生成的进程 ID 对于两个脚本都是相同的。

我将尝试使用每个脚本运行的唯一记录器名称,而不是“MyLog”。尽管可以从另一个进程获取记录器实例很奇怪。

4

4 回答 4

2

当两个脚本“同时运行”时,它们打印的行可以混合,这取决于操作系统如何为进程分配优先级。

因此,您可以在日志中获得类似以下内容:

x.py: /tmp/x.py
…
… # Other processes logging information
…
y.py: /tmp/y.py
x.py: site1  # Not printed by y!!
x.py: PID = 123
…
… # Other processes logging information
…
y.py: site2
y.py: PID = 124

如果您在每行前面加上每个程序基本名称,您是否仍然观察到问题?

于 2010-09-19T07:58:47.383 回答
2

一个 Python 进程不可能从另一个 Python 进程访问对象,除非为此使用例如multiprocessing模块做出特定规定。所以我不相信这就是正在发生的事情,无论表面上看起来多么像。

要确认这一点,请使用替代处理程序(例如 aFileHandlerRotatingFileHandler)来查看问题是否仍然存在。如果没有,那么您应该检查RotatingSqliteHandler逻辑。

如果是这样,并且如果您可以提出一个可重复演示该问题的小型独立脚本,请向 bugs.python.org 发布问题,我一定会看一看。(我维护 Python 日志记录包。)

于 2010-09-26T10:37:36.263 回答
0

这个问题让我很困惑:这是另一个想法!随机生成器可以使用“当前系统时间”播种(如果计算机上不存在随机数源)。在 Python 2.7 中,这是通过调用time.time(). 关键是并非所有系统都提供比 1 秒更精确的时间”。更一般地说,有时您的x.py和是否有可能y.py彼此足够接近,这time.time() 对于两个进程都是相同的,这样random.getrandbits(50)对它们产生相同的结果?正如您所观察到的,这将与仅出现异常的问题兼容。

您机器上的“分辨率”是time.time()多少(不同时间之间的最小间隔)?也许它足够大,可以让两个随机生成器以相同的方式异常地播种。

于 2010-09-20T20:11:04.767 回答
0

这可能与以下几点有关吗?

getLogger() 如果提供,则返回对具有指定名称的记录器实例的引用,否则返回 root。这些名称是以句点分隔的层次结构。多次调用具有相同名称的 getLogger() 将返回对同一记录器对象的引用。

您的两个脚本是否可以相互“连接”到足以发挥作用?例如,如果y.pyimport ,那么当你调用它们中的每一个时x.py,你都会得到相同的记录器。x.pyy.pylogging.getLogger('myLog')

于 2010-09-19T20:36:26.453 回答