我从未在this question中收到答案,所以我继续着通过其中描述的数据库在python进程之间共享数据的方法。现在,我的问题是从客户端Web浏览器jquery事件中有选择地,干净地(或根本没有)停止子进程而不终止主父进程。我的示例代码如下。 Flask通过按钮提供了一个简单的网页。当按下按钮时,将创建一个新的python进程,并获取数据。但是,再次按下按钮(停止数据获取)时,抛出了UnboundLocalError: local variable 'acquire_process' referenced before assignment
异常。此外,在另一个终端上运行$ ps -ef | grep python
命令时,主进程和创建的子进程都仍在运行,直到我抛出KeyboardInterrupt
为止。但是,这也杀死了主父进程,在我的实际项目中,该主进程需要继续向客户端提供其他内容。
我的问题是:按需从客户端jquery事件中有选择地启动和停止单个子python进程的最佳方法是什么?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time, os, random
import socket as sock
import psycopg2 as sql
import multiprocessing as mp
from flask_socketio import SocketIO, emit
from flask import Flask, render_template, url_for
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
app = Flask(__name__)
socket = SocketIO(app)
#Get the server's IP on which to serve app, client can navigate to IP
def get_ip_address():
""" Utility function to get the IP address of the device. """
ip_address = '127.0.0.1' # Default to localhost
s = sock.socket(sock.AF_INET, sock.SOCK_DGRAM)
try:
s.connect(('1.1.1.1', 1)) # Does not have to be reachable
ip_address = s.getsockname()[0]
finally:
s.close()
return ip_address
#create a table to store acquired data, erasing old data
def build_table():
conn_main = sql.connect('dbname=mp_example user=pi')
conn_main.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
cm = conn_main.cursor()
cm.execute('DROP TABLE IF EXISTS DAQ_example;')
cm.execute('CREATE TABLE DAQ_example \
(id SERIAL PRIMARY KEY,\
ch0 VARCHAR,\
ch1 VARCHAR,\
ch2 VARCHAR,\
ch3 VARCHAR);')
cm.close()
conn_main.close()
print('table built')
#function run in the process for acquiring data
def acquire_data():
print('acquire_data function called')
conn_fill = sql.connect('dbname=mp_example user=pi')
conn_fill.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
cf = conn_fill.cursor()
while True:
ch0 = random.random()
ch1 = random.random()
ch2 = random.random()
ch3 = random.random()
cf.execute('INSERT INTO DAQ_example\
(ch0, ch1, ch2, ch3)\
VALUES (%s, %s, %s, %s);', (ch0, ch1, ch2, ch3))
time.sleep(0.001)
#When client requests homepage
@app.route('/')
def render_index():
#serve the html
return render_template('index.html')
#Listen for client to start measurement
@socket.on('control_measurement_process')
def start_process(state):
#start a process to acquire data
if state == True:
build_table()
acquire_process = mp.Process(target=acquire_data)
acquire_process.start()
print('acquire_process')
print(os.system("ps -ef | grep python"))
#attempt to clean up acquire_process
elif state == False:
print('terminate bool called')
acquire_process.terminate()
print('acquire_process.terminate()')
print(os.system("ps -ef | grep python"))
if __name__ == '__main__':
print('main process')
print(os.system("ps -ef | grep python"))
#mp.set_start_method('spawn')
socket.run(app, host=get_ip_address(), port=8080)
“ index.html”如下:
<!DOCTYPE html>
<html>
<head>
<link
rel="stylesheet"
href="{{ url_for('static', filename='css/style.css') }}"
>
<link
rel="stylesheet"
href="{{ url_for('static', filename='bs/bootstrap-grid.css') }}"
>
<script
src="{{ url_for('static', filename='js/jquery-3.3.1.js') }}"
></script>
<script
src="{{ url_for('static', filename='js/socket.io.js') }}"
></script>
<script
src="{{ url_for('static', filename='js/bokeh-0.12.15.min.js') }}"
></script>
</head>
<body>
<div id="controls_title">
Controls:
</div>
<div id="controls" class="row">
<button id="measure" class="col-3">start<br>measurement</button>
</div>
<script>
<!-- jQuery here -->
var socket =
io.connect(location.origin, {transport: ['websocket']});
var allow_measurement = true;
//listens for client to start measurement acquisition
$("#measure").on("click", function() {
if ($("#measure").text() == "startmeasurement") {
$("#measure").html("stop<br>measurement");
allow_measurement = 1;
socket.emit("control_measurement_process",
state=allow_measurement);
}
else {
$("#measure").html("start<br>measurement");
allow_measurement = 0;
socket.emit("control_measurement_process",
state=allow_measurement);
}
});
</script>
</body>
</html>
答案 0 :(得分:0)
我终于意识到,每次按下jquery按钮时,start_process函数都会被调用干净,这就是为什么尚未分配局部变量的原因。我还找到了一种通过将start_process函数更改为以下内容来至少“终止”该过程的方法:
#Listen for client to start or stop the measurement
@socket.on('control_measurement_process')
def start_process(state):
#start a process to acquire data
if state == True:
build_table()
acquire_process = mp.Process(target=acquire_data,
name='acquire_process')
acquire_process.start()
print('acquire_process')
print(os.system("ps -ef | grep python"))
#attempt to clean up acquire_process
elif state == False:
print('terminate bool called')
#get all active children
children = mp.active_children()
for p in children:
#select only the process I want to stop
if p.name = 'acquire_process':
#at least defunct it
p.terminate()
print('acquire_process.terminate()')
print(os.system("ps -ef | grep python"))