优化“while”循环

优化“while”循环

我创建了一个迷你脚本,只需按一下按钮即可重新启动我的 Raspberry Pi。该脚本只是使用 WiringPi(gpio 命令)将引脚 0(按 Raspberry Pi 标准编号顺序的引脚 17)设置为输入,然后读取值直到为 1(即按下或按住按钮时)。

这是我的脚本:

gpio mode 0 in

while (true)
do
        if [ `gpio read 0` -eq 1 ]
        then
                echo password | sudo -S reboot
                break
        fi
done &

该脚本运行良好,一切都很好。

然而,对于那些不熟悉 Pi 的人来说,它配备的硬件资源非常有限(包括 512 MB 内存),很容易被我正在使用的循环所消耗。

我在这里想要实现的是找到另一种方法,让 bash 找出值何时从 更改为 ,01不必为其提供更像无条件循环的功能。这可行吗?请分享您的想法。

答案1

分析和现代解决方案

该脚本是一个繁忙的循环:它不断地一遍又一遍地读取 GPIO 引脚。它不会消耗太多内存,但会让CPU保持忙碌。

您应该将 GPIO 引脚设置为边缘模式。这gpio公用事业有一个wfi(等待中断)命令,可用于对边沿触发做出反应。 (gpio wfi提出问题时不存在。)

set -e
gpio mode 0 in
gpio wfi 0 rising
echo password | sudo -S reboot

Python 解决方案

有一个用于 GPIO 访问的 Python 库,支持边缘模式。这里有一些完全未经测试的 Python 代码,应该可以满足您的要求。

#!/usr/bin/env python
import os
from RPi import GPIO
GPIO.wait_for_edge(0, GPIO.RISING)
system("sudo reboot")

额外的 shell 提示

(true)可以写成true.括号创建了一个子进程,这是完全没有必要的。

`gpio read 0`应该用双引号引起来。如果没有引号,命令的输出将被视为文件名通配符模式的列表。使用双引号时,命令的输出将被视为字符串。始终在命令替换和变量替换两边加上双引号:"$(some_command)", "$some_variable"。另外,您应该使用语法$(…)而不是`…`: 它具有完全相同的含义,但是当命令很复杂时,反引号语法有一些解析怪癖。因此:if [ "$(gpio read 0)" -eq 1 ]

不要将 root 密码放入脚本中。如果脚本以 root 身份运行,则根本不需要 sudo。如果脚本不是以 root 身份运行,则授予运行脚本的用户sudo reboot无需提供密码即可运行的权限。运行visudo并添加以下行:

userwhorunsthescript ALL = (root) NOPASSWD: /sbin/reboot ""

请注意,如果 sudoers 文件中同一用户的条目需要密码,则该NOPASSWD条目必须位于后面。

一旦触发重新启动,您不需要打破循环,系统无论如何都会停止。

如果您决定继续使用此 shell 脚本,并且您的版本gpio太旧而无法使用wfi子命令,那么这里有一个改进的版本,它仅每秒检查按钮状态。请注意,由于引脚每秒仅读取一次,这意味着您需要按住按钮至少一秒钟以确保事件被拾取。

gpio mode 0 in
while sleep 1; do
    if [ "$(gpio read 0)" -eq 1 ]; then
        reboot
    fi
done &

答案2

你所拥有的被称为忙循环。你的循环几乎不会消耗任何内存,但会消耗大量的CPU。这通常可以通过添加sleep到循环体来缓解。

while (true)
do
        if [ `gpio read 0` -eq 1 ]
        then
                echo passowrd | sudo -S reboot
                break
        fi
        sleep 1
done &

摆脱繁忙循环将取决于gpio做什么。有些系统调用(例如select())可能会阻塞,直到文件描述符准备就绪。

就效率而言,()aroundtrue命令实际上是true在子 shell 中执行的。这不是必需的,可以用以下方式更好地表达:

while (( $(gpio read 0) != 1 )); do
    sleep 1
done
echo passowrd | sudo -S reboot

答案3

请尝试以下操作:

while ! gpio read 0 ; do
    sleep 1
done
echo password | sudo -S reboot

相关内容