免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 9323 | 回复: 17
打印 上一主题 下一主题

求助:python树莓派多线程编程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-03-27 17:13 |只看该作者 |倒序浏览
小弟初接触树莓派,想给孩子做一个孵化小鸡的孵化箱。构想是用5个18b20温度传感器分布于箱子内不同位置读取箱内温度,根据读取到的温度来通过gpio引脚控制继电器线包,继而控制电热丝加热,或者控制风扇来降温。如果箱内温度在设定范围内,则保持恒温(不加热也不降温)。同时还有lcd1602用来显示孵化时间/剩余时间等,7段数码管组依次显示5个温度值,三色led显示加热/降温/恒温状态,以及定时写入web页,开启一个简单web server,可以通过电脑手机等远程查看状态。主控程序结构大概如下:

  1. main():
  2.     while 1:
  3.         temp_lists=temp_get()//读取传感器的值到一个list
  4.         temp_avg=get_avg(temp_lists)//计算温度平均值
  5.         if (temp_avg>temp_max):
  6.             dis_hot() //若平均值大于设定上限,则持续降温
  7.         elif (temp_avg<temp_min):
  8.            hot() //若平均值小于下限,则持续加热
  9.        else:
  10.            keep_warming() //否则保温(不加热也不降温)
  11.        temp_display() //在数码管上依次显示5个传感器温度以及平均温度,每秒1个,共耗时6秒
复制代码
初步的程序已经调试通过,基本运行正常,但发现一个致命的问题是:数码管显示子程序因为要每隔1秒依次显示5组温度和平均温度,所以这个子程序需要花费6秒的时间。在这个子程序6秒的执行过程中,加热或降温子程序已经持续运行了6秒,有可能会使温度大大超出设定范围。所以想要把这个耗时较多的温度显示子程序设为多线程并发执行,使得它不要阻塞主程序中的其他部分。
我在网上看了不少关于python多线程的例子,也做了些试验,但一直也没能理出个头绪,所以还请诸位大侠打个帮手,毕竟已经答应了孩子,而且孩子都给小伙伴们许出赠送小鸡的承诺了。
火线求助!万分感谢!!!

论坛徽章:
22
2015年亚洲杯之科威特
日期:2015-04-18 15:27:07每日论坛发贴之星
日期:2016-01-27 06:20:0015-16赛季CBA联赛之广夏
日期:2016-03-28 16:20:51程序设计版块每日发帖之星
日期:2016-04-09 06:20:00CU十四周年纪念徽章
日期:2016-05-03 09:35:1415-16赛季CBA联赛之天津
日期:2016-11-18 08:31:3115-16赛季CBA联赛之山西
日期:2016-12-07 16:29:5315-16赛季CBA联赛之八一
日期:2017-01-10 11:34:3415-16赛季CBA联赛之吉林
日期:2017-03-30 22:51:1915-16赛季CBA联赛之广夏
日期:2017-04-13 20:51:52程序设计版块每日发帖之星
日期:2016-01-27 06:20:00每日论坛发贴之星
日期:2015-12-28 06:20:00
2 [报告]
发表于 2016-03-28 10:20 来自手机 |只看该作者
进来看看后,感觉很厉害的样子,看来楼主是搞科研的,这么有科学性,意义性的实验,在此预祝楼主取得成功哈。
但这个py版块,很多真正py高手估计都很少时间上来,楼主可能要耐心点等待一下py高手到来

论坛徽章:
0
3 [报告]
发表于 2016-03-28 15:18 |只看该作者
本帖最后由 amduroncn 于 2016-03-28 16:14 编辑

你应该建立一个线程同步事件,一个资源为1临界资源的访问的信号量


主线程 申请能临界区的使用-》测温》释放临界区访问-》发通知-》-----loop
显示线程 收通知-》重置事件-->申请临界区使用权-》快速复制一个副本-》释放临界区资源使用-》显示---loop


祝你小朋友成功孵出小鸡!


以下是代码
  1. # -*- coding: utf-8 -*-
  2. import threading
  3. import time
  4. import random
  5. # 建立一个继承threading的线程实现类

  6. temp_lists = []


  7. class DisplayClass(threading.Thread):
  8.     def __init__(self):
  9.         threading.Thread.__init__(self)
  10.         #  初始化各种变量

  11.     def run(self):
  12.         while 1:
  13.             ready.wait()  # 等待测温事件完成通知
  14.             ready.clear()  # 重置事件
  15.             sep.acquire()  # 对临界区访问,速度复制一个副本,
  16.             tmplists = temp_lists
  17.             tmpavg = temp_avg
  18.             sep.release()  # 释放临界区访问
  19.             print(u"显示温度"+str(tmplists)+ u",平均温度:"+str(tmpavg))
  20.             time.sleep(6)


  21. def temp_get():
  22.     # random.random()
  23.     temp_lists.append(random.random()*65)
  24.     if len(temp_lists) > 6:
  25.         temp_lists.pop(0)
  26.     return temp_lists


  27. def get_avg(l):
  28.     return sum(l)/len(l)


  29. def dis_hot():
  30.     pass


  31. def keep_warming():
  32.     pass


  33. def hot():
  34.     pass

  35. def main():
  36.     global temp_lists
  37.     global temp_avg
  38.     global ready
  39.     global sep;
  40.     temp_max = 40
  41.     temp_min = 35
  42.     ready = threading.Event()
  43.     sep = threading.Semaphore(1)
  44.     ready.clear()
  45.     threaddisdis = DisplayClass()
  46.     threaddisdis.start()
  47.     while 1:
  48.         sep.acquire()
  49.         temp_lists = temp_get()  # 读取传感器的值到一个list
  50.         temp_avg = get_avg(temp_lists)  # 计算温度平均值
  51.         sep.release()
  52. # 发出通知显示线程可以执行
  53.         ready.set()

  54.         if temp_avg > temp_max:
  55.             dis_hot()  # 若平均值大于设定上限,则持续降温
  56.             print(u'降温')
  57.         elif temp_avg < temp_min:
  58.             hot()  # 若平均值小于下限,则持续加热
  59.             print(u'加热')
  60.         else:
  61.             keep_warming()   # 否则保温(不加热也不降温)
  62.             print(u'保温')
  63.         time.sleep(1)
  64. if __name__ == "__main__":
  65.     main()
复制代码

评分

参与人数 1信誉积分 +10 收起 理由
Windows19 + 10 这个思路我给满分10分

查看全部评分

论坛徽章:
0
4 [报告]
发表于 2016-03-28 22:43 |只看该作者
回复 2# Windows19

谢谢您的关注,厉害可不敢当,接触python的时间不多,所以有点一筹莫展了。
   

论坛徽章:
0
5 [报告]
发表于 2016-03-28 22:49 |只看该作者
回复 3# amduroncn


非常感谢您如此具体的指教和帮助!我这就去试试看。关于python的多线程编程,我还只停留在start,join和setdeamon等函数上,希望能进一步请教您。谢谢!

论坛徽章:
0
6 [报告]
发表于 2016-03-29 00:21 |只看该作者
本帖最后由 amduroncn 于 2016-03-29 00:30 编辑

不用客气,我也是初学。从你的描叙来看,6秒就会使温度超出范围,可见你的发热丝,功率貎似得大啊。何不使用PWM控制发热丝,发热丝可以用低压的发热丝(安全),结合PID控制,可把温度做得很恒定哟。你现在的方案,继电器会经常动作吗?

论坛徽章:
11
2015年迎新春徽章
日期:2015-03-04 09:55:282017金鸡报晓
日期:2017-02-08 10:39:4215-16赛季CBA联赛之辽宁
日期:2016-12-15 10:24:1715-16赛季CBA联赛之佛山
日期:2016-11-30 09:04:2015-16赛季CBA联赛之江苏
日期:2016-04-29 15:56:1215-16赛季CBA联赛之同曦
日期:2016-04-12 13:21:182016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之山东
日期:2016-02-16 11:37:52每日论坛发贴之星
日期:2016-02-07 06:20:00程序设计版块每日发帖之星
日期:2016-02-07 06:20:0015-16赛季CBA联赛之新疆
日期:2018-01-09 16:25:37
7 [报告]
发表于 2016-03-29 15:06 |只看该作者
import multiprocessing

def main():
    pool = multiprocessing.Pool(5)
    old = 0,0
    while 1:
        temp_lists=temp_get()#读取传感器的值到一个list
        temp_avg=get_avg(temp_lists)#计算温度平均值
        if (temp_avg>temp_max):
            dis_hot() #若平均值大于设定上限,则持续降温
        elif (temp_avg<temp_min):
            hot() #若平均值小于下限,则持续加热
        else:
            keep_warming() #否则保温(不加热也不降温)
        if old == (temp_lists,temp_avg):
            continue
        old = (temp_lists,temp_avg) #控制一下不要做可有可无的调用
        pool.apply_async(temp_display)
        ##temp_display() #在数码管上依次显示5个传感器温度以及平均温度,每秒1个,共耗时6秒

评分

参与人数 1信誉积分 +10 收起 理由
Windows19 + 10

查看全部评分

论坛徽章:
0
8 [报告]
发表于 2016-03-29 19:53 |只看该作者
bskay 发表于 2016-03-29 15:06
import multiprocessing

def main():
说下这个思路的几个问题
1数码管与液晶不同,它是一个需要不停扫描才能显示显示的器件,如果几个温度相同,就不进行显示,数码管会没有输出。当然1602是可以正常显示的。  

所以
if old == (temp_lists,temp_avg):
            continue
old = (temp_lists,temp_avg) #控制一下不要做可有可无的调用
对数码管来说是错误的,它会导致数码管无显示。

2.bskay使用了进程池,这可以充分利用多核cpu的各个核心,但bskay开了5个进程,这是没必要的且是错误的。主线程的一个loop是很快的(不加sleep,测5个18b20,最多ms级吧),而显示进程是很慢的,主线程一个loop下来,就会有一个进程被产生出来(<=5)基本上瞬间就会使进程池满掉,造成主线程阻塞。

而且依楼主意思楼主只有一个数码管,是依次做的扫描。btw,你得把数据传进去,否则进程显示什么呢?

论坛徽章:
11
2015年迎新春徽章
日期:2015-03-04 09:55:282017金鸡报晓
日期:2017-02-08 10:39:4215-16赛季CBA联赛之辽宁
日期:2016-12-15 10:24:1715-16赛季CBA联赛之佛山
日期:2016-11-30 09:04:2015-16赛季CBA联赛之江苏
日期:2016-04-29 15:56:1215-16赛季CBA联赛之同曦
日期:2016-04-12 13:21:182016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之山东
日期:2016-02-16 11:37:52每日论坛发贴之星
日期:2016-02-07 06:20:00程序设计版块每日发帖之星
日期:2016-02-07 06:20:0015-16赛季CBA联赛之新疆
日期:2018-01-09 16:25:37
9 [报告]
发表于 2016-03-30 11:16 |只看该作者
本帖最后由 bskay 于 2016-03-30 11:29 编辑

回复 8# amduroncn


主线程一个loop下来,就会有一个进程被产生出来(<=5)基本上瞬间就会使进程池满掉,造成主线程阻塞。

最好先实地验证一下,验证过是没有关系的


if old == (temp_lists,temp_avg):
            continue

只是相同的不去显示,因为前一次的显示过程可能还没有完成,没有什么影响(逻辑上肯定没有问题的,如果长时间保持恒温..做不做都没有关系的)

论坛徽章:
0
10 [报告]
发表于 2016-03-30 13:33 |只看该作者
回复 9# bskay


    以前看到apply_async说是池满了,会阻塞主线程。实验了一下不会。我说错了。这个方法可行,只要将POOL(1)即可。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP