【问题标题】:Run a script with web server and maintain data to be used later使用 Web 服务器运行脚本并维护数据以供以后使用
【发布时间】:2014-03-23 06:22:17
【问题描述】:

注意:我想在不使用任何框架的情况下实现它。

我必须使用 python 创建一个 Web 应用程序。应用程序应保持过去 60 秒内每个进程的 CPU 使用率的运行平均值。它应该充当 Web 服务器,当它收到请求时,它应该返回每个进程的当前平均值。以下是我编写的脚本。 record_usage.py 是我想在 server.py 运行后立即运行的脚本。这样它就可以运行并维护 cpu 使用数据,我打算在收到 XHR 请求并将其发送回客户端时读取这些数据。

那么,我的问题是如何调用此要求?我尝试在启动服务器后使用 subprocess.POPEN 运行 record_usage.pyrecord_usage.py 也开始在后台运行。但是当我尝试访问它创建的数据时,我创建的类对象不是它使用的对象,而是一个新对象。如何完成此链接?

请询问我无法说清楚的事情。

server.py 的最新变化

if __name__ == '__main__':
    RU_OBJ = RU(settings.SAMPLING_FREQ, settings.AVG_INTERVAL)
    RU_LOCK = RLock()
    # Record CPU usage in a thread.
    ru_thread = Thread(target=RU_OBJ.record, args=(RU_LOCK,))
    ru_thread.daemon = True
    ru_thread.start()

    # Run server.
    run()

record_usage.py 的最新变化

def record(self, lock):
    while True:
        with lock:
            self.add_processes()
        time.sleep(self.sampling_freq)

这是应用锁的正确方法吗?读取进程信息时应用了类似的锁。行得通吗?

新增功能:

def add_processes(self,):
    for _process in psutil.process_iter():
        try:
            new_proc = _process.as_dict(attrs=['cpu_times', 'name', 'pid',
                                               'status'])
        except psutil.NoSuchProcess:
            continue
        pid, (user, _sys) = new_proc['pid'], new_proc.pop('cpu_times')
        # Get or create details object for the process.
        existing = self.processes.setdefault(pid, new_proc)
        # Get or create queue object for the CPU times of the process.
        queue_dict = self.process_queue.setdefault(pid, dict())
        # User CPU time.
        user_q = queue_dict.setdefault('user_q', PekableQueue(self.avg_interval))
        user_q.enqueue(user)
        user_avg = get_avg(user_q)
        # System CPU time.
        sys_q = queue_dict.setdefault('sys_q', PekableQueue(self.avg_interval))
        sys_q.enqueue(_sys)
        sys_avg = get_avg(sys_q)
        # Update the details object for the process.
        existing.update(user_avg=user_avg, sys_avg=sys_avg, **new_proc)

def get_curr_processes(self):
    return [self.processes[pid] for pid in psutil.get_pid_list()
            if pid in self.processes]

【问题讨论】:

  • 不清楚“这个要求”指的是什么。最简单的解决方案是在不同的线程而不是不同的进程中收集统计信息
  • @JFSebastian 这个要求是将统计信息传送到服务器。你能用一个小例子来使用线程吗?
  • 你为什么认为你需要一个锁?
  • 因为字典在阅读时可能会被修改。因此,差异过程的数据可能在它们产生的时间方面存在不一致。我想错了吗?
  • 什么字典?锁保护的代码越少越好(在字典附近使用它,不要包装整个方法)。除非在至少两个线程中使用,否则锁是无用的。你不需要RLock,除非你需要递归获取它

标签: python web-applications process subprocess


【解决方案1】:

在另一个线程中收集统计信息:

if __name__ == '__main__':
    from threading import Thread, Lock
    import record_usage

    lock = Lock()
    t = Thread(target=record_usage.record, args=[lock])
    t.daemon = True
    t.start()

    run(lock)

如果您在一个线程中更改某些共享数据并在另一个线程中读取它,那么您可以使用锁保护您访问/更改值的位置:

#...
with self.lock:
    existing = self.processes.setdefault(pid, new_proc)
#...
with self.lock:
    existing.update(user_avg=user_avg, sys_avg=sys_avg, **new_proc)
#...

def get_curr_processes(self):
    with self.lock:
        return [self.processes[pid] for pid in psutil.get_pid_list()
                if pid in self.processes]

self.lock 在所有线程中必须是同一个对象。如果self.processesdict,那么你不需要在CPython 中使用锁。这些方法在 C 中实现,解释器在调用它们时不会释放 GIL(全局锁),即一次只有一个线程访问 dict

【讨论】:

  • @jfsebastian 我在最后的问题陈述中做了一些编辑。这与在线程上应用锁有关。这是正确的方法吗?我没有看到任何例外。但是我怎么知道锁是否在工作呢?
  • 同样适用于列表吗?
猜你喜欢
  • 2018-12-21
  • 2012-10-28
  • 2011-11-27
  • 2011-11-29
  • 1970-01-01
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多