Pico W+MicroPython用_thread实现WebServer与数据处理并行的问题
问题与解决方案:Pico W MicroPython 并行Web服务器与数据处理
遇到的问题
- 问题1:使用
_thread运行Web服务器和数据处理函数时,Web服务器会挂起,直到数据处理函数执行完毕才响应浏览器请求,无法实时查看运行状态。 - 问题2:运行Web服务器时,数据处理函数中的
urequests.get抛出[Errno 103] ECONNABORTED错误,无法正常发起HTTP请求。
原问题代码
import utime, machine, urequests, json, network, socket, _thread led = machine.Pin("LED", machine.Pin.OUT) def connect(): global wlan wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect("SSID", "PASSS") while wlan.isconnected() == False: print("Connecting...") led.off() utime.sleep_ms(100) led.on() utime.sleep_ms(100) led.off() utime.sleep_ms(100) led.on() utime.sleep_ms(100) led.on() ip = wlan.ifconfig()[0] print(f'Connected on {ip}') return ip def open_socket(ip): address = (ip, 80) connection = socket.socket() connection.bind(address) connection.listen(1) return connection def webpage(steps): html = f""" <!DOCTYPE html> <html> <head> <title>Pico 2</title> </head> <body> <p>{steps}</p> </body> </html> """ return str(html) def pushgetdata(): while wlan.isconnected() == True: try: global steps led.off() utime.sleep_ms(300) led.on() steps = "Step 1: Reading values from sensor one...<br>" #function to read data from one sensor here #... #... #... led.off() utime.sleep_ms(100) led.on() steps = steps + "Step 2: Reading values from sensor two...<br>" #function to read data from other sensor here #... #... #... led.off() utime.sleep_ms(100) led.on() steps = steps + "Step 3: Pushing and getting results...<br>" jsondata = urequests.get("https://xxx.xxx.xxx/api/?device=pico2&sensor1=valulesfromsensor1&sensor2=valuesfromsensor2") proceseddata = jsondata.json() steps = steps + proceseddata + "<br>" steps = steps + "Step 4: Doing things with results...<br>" #function to do conditions and things with results... #... #... #... jsondata.close() steps = steps + "Step 5: Finished, sleeping for the next round...<br>" utime.sleep_ms(100) led.off() utime.sleep_ms(100) led.on() utime.sleep(900) except OSError as e: steps = steps + e def serve(connection): while True: try: client, addr = connection.accept() print('client connected from', addr) request = client.recv(1024) request = str(request) html = webpage(steps) client.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') client.send(html) client.close() except OSError as e: client.close() def webserver(): ip = connect() connection = open_socket(ip) _thread.start_new_thread(serve,(connection,)) try: webserver() pushgetdata() except KeyboardInterrupt: machine.reset()
问题1解决方案:线程阻塞与实时响应修复
核心问题
原代码中pushgetdata的utime.sleep(900)是长阻塞睡眠,会占据主线程,导致MicroPython的线程调度无法及时切换到Web服务器线程;同时全局变量steps的并发读写可能出现数据不一致。
修改要点
- 拆分长睡眠:把
utime.sleep(900)拆分为多次短睡眠,给线程切换留足时机 - 线程安全锁:用
_thread.allocate_lock()保护steps变量的读写操作
修改后关键代码
# 全局锁,保护steps变量的并发访问 lock = _thread.allocate_lock() steps = "" def pushgetdata(): global steps while wlan.isconnected() == True: try: # 写入steps时加锁 with lock: steps = "Step 1: Reading values from sensor one...<br>" led.off() utime.sleep_ms(300) led.on() # 传感器读取逻辑... with lock: steps += "Step 2: Reading values from sensor two...<br>" led.off() utime.sleep_ms(100) led.on() # 传感器读取逻辑... with lock: steps += "Step 3: Pushing and getting results...<br>" # 后续请求逻辑... with lock: steps += "Step 5: Finished, sleeping for the next round...<br>" led.off() utime.sleep_ms(100) led.on() # 拆分900秒睡眠为9000次100ms睡眠,触发线程切换 for _ in range(9000): utime.sleep_ms(100) except OSError as e: with lock: steps += str(e) + "<br>" def serve(connection): global steps while True: try: client, addr = connection.accept() print('client connected from', addr) request = client.recv(1024) request = str(request) # 读取steps时加锁 with lock: html = webpage(steps) client.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') client.send(html) client.close() except OSError as e: client.close()
问题2解决方案:urequests连接中止错误修复
核心原因
MicroPython网络栈资源有限,Web服务器监听与urequests请求可能存在资源竞争;同时无超时设置的请求容易被远端中止。
修复要点
- 添加请求超时:给
urequests.get设置超时参数,避免长时间阻塞 - 自动管理连接:用
with语句自动关闭响应对象,避免资源泄漏 - 调整线程启动顺序:让Web服务器线程在主线程运行,数据处理在子线程,优化资源调度
修改后关键代码
# 调整主逻辑的线程启动顺序 try: ip = connect() connection = open_socket(ip) # 先启动数据处理子线程,主线程运行Web服务器 _thread.start_new_thread(pushgetdata, ()) serve(connection) except KeyboardInterrupt: machine.reset() # 修改pushgetdata中的请求逻辑 with urequests.get("https://xxx.xxx.xxx/api/?device=pico2&sensor1=valulesfromsensor1&sensor2=valuesfromsensor2", timeout=5) as jsondata: proceseddata = jsondata.json() with lock: steps += str(proceseddata) + "<br>" steps += "Step 4: Doing things with results...<br>"
内容的提问来源于stack exchange,提问作者Bararto
相关产品推荐
相关产品推荐

