在多处理或多线程应用程序中保留cpu-time

时间:2018-02-05 12:29:07

标签: python multithreading multiprocessing python-3.6 python-asyncio

我正在开发一个带有Raspberry Pi 3的项目,用于环境控制,在连续循环中有许多简单的重复事件。 RP3对于这项工作来说是过于资格的,但它让我专注于其他事情。

申请特征:

  1. 应用程序应从十几个传感器(温度,湿度,pH,ORP等)收集感应数据(可变间隔n秒)。
  2. 根据时间和这些感应数据,控制器计算输出(开关,阀门和PWM驱动器)。
  3. 几乎没有事件需要按顺序运行。
  4. 某些事件属于“安全”类别,应在触发时立即运行(故障安全传感器,紧急按钮)。
  5. 大多数事件在几秒钟内重复运行(每秒,直到每30秒)。
  6. 某些事件触发一个动作,在1到120秒内激活一个继电器。
  7. 某些事件使用基于时间的值。这个值需要每天计算几次并且相当CPU密集(使用一些迭代插值公式,因此具有变量运行时)。
  8. 显示环境状态(连续循环)
  9. 我熟悉(不是专业)VB.NET,但决定在Python 3.6中完成这个项目。 最近几个月我读了很多关于设计模式,线程,流程,事件,并行处理等主题的文章。

    根据我的阅读,我认为Asyncio与Executor中的一些任务相结合可以完成这项任务。

    大多数任务/事件不是时间关键的。控制器输出可以使用'最新'的sensordata。 另一方面,一些任务在一段时间内激活继电器。我想知道如何编程这些任务,而没有机会另一个“耗时”的任务是阻止处理器在一段时间内(例如)CO2阀打开。这对我的环境来说可能是灾难性的。

    因此我需要一些建议。

    到目前为止,请参阅下面的代码。我不确定我是否正确使用了Python中的Asyncio函数。 为了便于阅读,我将把各种任务的内容存储在不同的模块中。

    import asyncio
    import concurrent.futures
    import datetime
    import time
    import random
    import math
    
    # define a task...
    async def firstTask():
        while True:
            await asyncio.sleep(1)
            print("First task executed")
    
    # define another task...        
    async def secondTask():
        while True:
            await asyncio.sleep(5)
            print("Second Worker Executed")
    
    # define/simulate heavy CPU-bound task
    def heavy_load():
        while True:
            print('Heavy_load started')
            i = 0
            for i in range(50000000):
                f = math.sqrt(i)*math.sqrt(i)
            print('Heavy_load finished')
            time.sleep(4)
    
    def main():
    
        # Create a process pool (for CPU bound tasks).
        processpool = concurrent.futures.ProcessPoolExecutor()
    
        #  Create a thread pool (for I/O bound tasks).
        threadpool = concurrent.futures.ThreadPoolExecutor()
    
        loop = asyncio.get_event_loop()
    
        try:
            # Add all tasks. (Correct use?)
            asyncio.ensure_future(firstTask())
            asyncio.ensure_future(secondTask())
            loop.run_in_executor(processpool, heavy_load)
            loop.run_forever()
        except KeyboardInterrupt:
            pass
        finally:
            print("Loop will be ended")
            loop.close()    
    
    if __name__ == '__main__':
        main()
    

2 个答案:

答案 0 :(得分:1)

  

大多数任务/事件不是时间关键的。控制器输出可以使用'最新'的sensordata。另一方面,一些任务在一段时间内激活继电器。我想知道如何编程这些任务,而没有机会另一个“耗时”的任务是阻止处理器在一段时间内(例如)CO2阀打开。这对我的环境来说可能是灾难性的。

请允许我强调Python 不是实时语言,而asyncio不是实时组件。它们既不运行实时执行的基础设施(Python是垃圾收集的,通常在分时系统上运行),也没有在实践中在这样的环境中进行过测试。因此,我强烈建议不要在任何情况下使用它们,因为错误可能会对您的环境造成灾难。

有了这个,你的代码就会出现问题:虽然heavy_load计算不会阻止事件循环,但它永远不会完成,也不会提供有关其进度的信息。 run_in_executor背后的想法是,您正在运行的计算最终将停止,并且事件循环将希望得到有关它的通知。 run_in_executor的惯用法可能如下所示:

def do_heavy_calc(param):
    print('Heavy_load started')
    f = 0
    for i in range(50000000):
        f += math.sqrt(i)*math.sqrt(i)
    return f

def heavy_calc(param):
    loop = asyncio.get_event_loop()
    return loop.run_in_executor(processpool, do_heavy_calc)

表达式heavy_calc(...)不仅在不阻塞事件循环的情况下运行,而且还等待。这意味着异步代码可以等待其结果,也不会阻止其他协同程序:

async def sum_params(p1, p2):
    s1 = await heavy_calc(p1)
    s2 = await heavy_calc(p2)
    return s1 + s2

上面一个接一个地运行两个计算。它也可以并行完成:

async def sum_params_parallel(p1, p2):
    s1, s2 = await asyncio.gather(heavy_calc(p1), heavy_calc(p2))
    return s1 + s2

可以改进的另一件事是设置代码:

asyncio.ensure_future(firstTask())
asyncio.ensure_future(secondTask())
loop.run_in_executor(processpool, heavy_load)
loop.run_forever()

调用asyncio.ensure_future然后从不等待结果有点像asyncio反模式。无拘无束的任务引发的例外情况被默默地吞噬,这几乎肯定不是你想要的。有时候人们只是忘记写await,这就是为什么asyncio会在循环被破坏时抱怨未被挂起的待处理任务的原因。

安排某人等待每项任务的良好编码习惯,可以立即使用awaitgather将其与其他任务相结合,或者在以后点。例如,如果任务需要在后台运行,您可以将其存储在某处await或在应用程序生命周期结束时取消它。在您的情况下,我会将gatherloop.run_until_complete合并:

everything = asyncio.gather(firstTask(), secondTask(),
                           loop.run_in_executor(processpool, heavy_load))
loop.run_until_complete(everything)

答案 1 :(得分:0)

  

某些事件属于"安全"并且应该在触发时立即运行(故障安全传感器,紧急按钮)。

然后我强烈建议您不要依赖软件来实现此功能。切断电源的紧急停止按钮是通常完成的事情。如果你有软件这样做,并且你真的有一个面临生命危险的处境,你就会陷入一堆祸患中 - 几乎可以肯定你需要遵守大量的法规。遵守。