Flask 비동기 임무 수행
어떻게 이 루어 지지?
스 레 드 사용 방식
시간 이 걸 리 는 임 무 를 수행 하려 면 새로운 스 레 드 를 열 어 임 무 를 수행 하 는 방식 이 가장 간단 하고 빠르다.
Thread PoolExecutor 를 통 해 이 루어 집 니 다.
from flask import Flask
from time import sleep
from concurrent.futures import ThreadPoolExecutor
# DOCS https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor
#
executor = ThreadPoolExecutor(2)
app = Flask(__name__)
@app.route('/jobs')
def run_jobs():
#
executor.submit(long_task, 'hello', 123)
return 'long task running.'
#
def long_task(arg1, arg2):
print("args: %s %s!" % (arg1, arg2))
sleep(5)
print("Task is done!")
if __name__ == '__main__':
app.run()
비교적 간단 한 시간 소모 임 무 를 수행 하려 면 이런 방식 을 사용 할 수 있다.예 를 들 어 메 일 을 보 내 거나 문자 인증 코드 를 보 내 는 등 이다.그러나 이런 방식 에는 전단 에서 임무 수행 상 태 를 알 수 없다 는 문제 가 있다.
전단 에서 알 고 싶 으 면 논 리 를 설계 해 야 합 니 다.예 를 들 어 작업 수행 상 태 를 redis 에 저장 하고 유일한 작업 id 를 통 해 표 지 를 한 다음 에 인 터 페 이 스 를 작성 하고 작업 id 를 통 해 작업 의 상 태 를 얻 은 다음 에 전단 에서 정시 에 이 인 터 페 이 스 를 요청 하여 작업 상태 정 보 를 얻 도록 해 야 합 니 다.
모든 것 을 스스로 실현 하 는 것 은 좀 번 거 로 워 보이 지만,셀 러 리 는 마침 이런 논 리 를 실현 하여 사용 해 보 았 다.
Celery 사용 하기
전단 에서 퀘 스 트 상 태 를 얻 을 수 있 는 수 요 를 충족 시 키 기 위해 셀 러 리 를 사용 할 수 있다.
Celery 는 실시 간 작업 처리 와 스케줄 링 의 분포 식 작업 대기 열 로 웹 비동기 작업,정시 작업 등에 자주 사용 되 며,뒤에 Celery 의 구 조 를 묘사 하 는 글 을 따로 쓰 고 있 으 며,여 기 는 깊이 토론 하지 않 습 니 다.
지금 나 는 전단 이 하나의 진도 조 를 통 해 백 엔 드 임무 의 집행 상황 을 판단 할 수 있 도록 하고 싶다.Celery 를 사용 하면 쉽게 이 루어 집 니 다.먼저 pip 를 통 해 Celery 와 redis 를 설치 합 니 다.redis 를 설치 하려 는 이 유 는 Celery 가 redis 를'메시지 에이전트/메시지 미들웨어'로 선택 하 게 하기 때 문 입 니 다.
pip install celery
pip install redis
Flask 에서 Celery 를 사용 하 는 것 은 사실 매우 간단 하 다.여기 서 Flask 에서 Celery 를 사용 하 는 전체적인 절 차 를 간단하게 살 펴 본 다음 에 구체 적 인 프로젝트 를 실현 한다.1.Flask 에서 Celery 초기 화
from flask import Flask
from celery import Celery
app = Flask(__name__)
#
# , , redis URL
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
# Celery
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'
# Celery
celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
# Flask Celery
celery.conf.update(app.config)
상기 코드 에서 Celery 클래스 를 통 해 celery 대상 을 초기 화하 고 들 어 오 는 응용 이름과 메시지 에이전트 의 연결 URL 입 니 다.2.celery.task 장식 기 를 통 해 작업 에 대응 하 는 함수 장식
@celery.task
def long_task(arg1, arg2):
#
return result
3.Flask 에서 정 의 된 인 터 페 이 스 는 비동기 방식 으로 시간 소모 작업 을 수행 합 니 다.
@app.route('/', methods=['GET', 'POST'])
def index():
task = long_task.delay(1, 2)
delay () applyasync () ,applyasync () , , long_task ()
@app.route('/', methods=['GET', 'POST'])
def index():
task = long_task.apply_async(args=[1, 2], countdown=60)
delay()와 applyasync()는 작업 대상 을 되 돌려 줍 니 다.이 대상 은 작업 의 상태 와 각종 관련 정 보 를 얻 을 수 있 습 니 다.이 세 단 계 를 통 해 셀 러 리 를 사용 할 수 있다.
이 어'전단 이 하나의 진도 조 를 통 해 백 엔 드 임무 의 집행 상황 을 판단 할 수 있 도록'하 는 수 요 를 구체 적 으로 실현 한다.
# bind True, self
@celery.task(bind=True)
def long_task(self):
verb = ['Starting up', 'Booting', 'Repairing', 'Loading', 'Checking']
adjective = ['master', 'radiant', 'silent', 'harmonic', 'fast']
noun = ['solar array', 'particle reshaper', 'cosmic ray', 'orbiter', 'bit']
message = ''
total = random.randint(10, 50)
for i in range(total):
if not message or random.random() < 0.25:
#
message = '{0} {1} {2}...'.format(random.choice(verb),
random.choice(adjective),
random.choice(noun))
# Celery
self.update_state(state='PROGRESS',
meta={'current': i, 'total': total,
'status': message})
time.sleep(1)
#
return {'current': 100, 'total': 100, 'status': 'Task completed!',
'result': 42}
상기 코드 에서 celery.task()장식 기 는 bid=True 인 자 를 사 용 했 습 니 다.이 인 자 는 Celery 가 Celery 자 체 를 전송 하여 작업 상 태 를 기록 하고 업데이트 할 수 있 습 니 다.그 다음 에 for 교체,교체 의 논 리 는 의미 가 없다.즉,list 에서 무 작위 로 일부 어 휘 를 추출 하여 논리 적 인 운행 을 모 의 하 는 것 이다.이것 은 시간 이 걸 리 는 논리 임 을 나타 내기 위해 time.sleep(1)을 통 해 1 초 동안 휴면 하 는 것 이다.
단 어 를 한 번 가 져 올 때마다 self.updatestate()는 Celery 작업 의 상 태 를 업데이트 합 니 다.Celery 는 SUCCESS,STARTED 등 내 장 된 상 태 를 포함 하고 있 습 니 다.여 기 는 사용자 정의 상태 인'PROGRESS'를 사 용 했 습 니 다.상 태 를 제외 하고 이번 순환 의 일부 정 보 를 meta 매개 변수(메타 데이터)를 통 해 사전 으로 저장 합 니 다.이 데이터 가 있 으 면 전단 에 진도 표를 표시 할 수 있다.
시간 소모 방법 을 정의 한 후,이 시간 소모 방법 을 사용 할 Flask 인터페이스 방법 을 정의 합 니 다.
@app.route('/longtask', methods=['POST'])
def longtask():
#
task = long_task.apply_async()
# 202, Location
return jsonify({}), 202, {'Location': url_for('taskstatus',
task_id=task.id)}
쉽게 말 하면 전단 은 POST 를 통 해/longtask 에 요청 하여 백 엔 드 에서 시간 이 걸 리 는 작업 을 시작 합 니 다.되 돌아 오 는 상태 코드 202,202 는 보통 요청 이 진행 중 임 을 나타 내 고 패 킷 을 되 돌려 주 는 헤더(Header)에 Location 헤더 정 보 를 추가 합 니 다.전단 은 패 킷 에 있 는 Header 의 Location 정 보 를 읽 어 작업 id 에 대응 하 는 전체 url 을 가 져 올 수 있 습 니 다.
전단 에 작업 id 에 대응 하 는 url 이 있 으 면 전단 에 인 터 페 이 스 를 제공 하여 전단 이 작업 id 를 통 해 현재 시간 작업 의 구체 적 인 상 태 를 가 져 올 수 있 도록 해 야 합 니 다.
@app.route('/status/<task_id>')
def taskstatus(task_id):
task = long_task.AsyncResult(task_id)
if task.state == 'PENDING': #
response = {
'state': task.state,
'current': 0,
'total': 1,
'status': 'Pending...'
}
elif task.state != 'FAILURE': #
response = {
'state': task.state, #
# meta , task.info.get()
'current': task.info.get('current', 0), #
'total': task.info.get('total', 1), #
'status': task.info.get('status', '')
}
if 'result' in task.info:
response['result'] = task.info['result']
else:
#
response = {
'state': task.state,
'current': 1,
'total': 1,
'status': str(task.info), #
}
return jsonify(response)
작업 대상 의 정 보 를 얻 기 위해 작업 id 를 사용 하여 AsyncResult 류 를 초기 화하 고 작업 대상 을 얻 은 다음 작업 대상 에서 현재 작업 의 정 보 를 얻 을 수 있 습 니 다.이 방법 은 JSON 으로 되 돌아 갑 니 다.작업 상태 와 meta 에서 지정 한 정 보 를 포함 하고 전단 은 이 정 보 를 이용 하여 진행 조 를 구축 할 수 있 습 니 다.
만약 에 작업 이 PENDING 상태 에 있다 면 이 작업 이 아직 시작 되 지 않 았 음 을 나타 낸다.이런 상태 에서 작업 에 아무런 정보 가 없다.여기 서 인위적으로 데 이 터 를 되 돌려 준다.작업 수행 에 실패 하면 task.info 에 포 함 된 이상 정 보 를 되 돌려 줍 니 다.그 밖 에 정상적으로 실 행 했 습 니 다.정상적으로 실행 하면 task.info 를 통 해 작업 의 구체 적 인 정 보 를 얻 을 수 있 습 니 다.
이렇게 하면 백 엔 드 의 논리 처리 가 완 료 됩 니 다.그 다음 에 전단 의 논 리 를 실현 합 니 다.도형 진도 조 를 실현 하려 면 nanobar.js 를 직접 사용 할 수 있 습 니 다.간단 한 두 마디 로 진도 조 를 실현 할 수 있 습 니 다.홈 페이지 의 예 는 다음 과 같 습 니 다.
var options = {
classname: 'my-class',
id: 'my-id',
//
target: document.getElementById('myDivId')
};
//
var nanobar = new Nanobar( options );
nanobar.go( 30 ); // 30%
nanobar.go( 76 ); // 76%
// 100% ,
nanobar.go(100);
nanobar.js 가 있 으 면 아주 간단 합 니 다.먼저 간단 한 HTML 인터페이스 를 정의 합 니 다.
<h2>Long running task with progress updates</h2>
<button id="start-bg-job">Start Long Calculation</button><br><br>
<div id="progress"></div>
자 바스 크 립 트 를 통 해 배경 에 대한 요청 을 실현 합 니 다.
//
$(function() {
$('#start-bg-job').click(start_long_task);
});
// longtask
function start_long_task() {
// html
div = $('<div class="progress"><div></div><div>0%</div><div>...</div><div> </div></div><hr>');
$('#progress').append(div);
//
var nanobar = new Nanobar({
bg: '#44f',
target: div[0].childNodes[0]
});
// ajax longtask
$.ajax({
type: 'POST',
url: '/longtask',
// , Location
success: function(data, status, request) {
status_url = request.getResponseHeader('Location');
// update_progress()
update_progress(status_url, nanobar, div[0]);
},
error: function() {
alert('Unexpected error');
}
});
}
//
function update_progress(status_url, nanobar, status_div) {
// getJSON() JQuery , Location url , 「/status/<task_id>」
$.getJSON(status_url, function(data) {
//
percent = parseInt(data['current'] * 100 / data['total']);
//
nanobar.go(percent);
//
$(status_div.childNodes[1]).text(percent + '%');
$(status_div.childNodes[2]).text(data['status']);
if (data['state'] != 'PENDING' && data['state'] != 'PROGRESS') {
if ('result' in data) {
//
$(status_div.childNodes[3]).text('Result: ' + data['result']);
}
else {
//
$(status_div.childNodes[3]).text('Result: ' + data['state']);
}
}
else {
// 2
setTimeout(function() {
update_progress(status_url, nanobar, status_div);
}, 2000);
}
});
}
주석 을 통 해 코드 의 전체 논 리 를 읽 을 수 있 습 니 다.이로써 수요 가 다 이 루어 졌 으 니 운행 해 보 자.
우선 레 디 스 실행
redis-server
그리고 celery 를 실행 합 니 다.
celery worker -A app.celery --loglevel=info
마지막 으로 Flask 프로젝트 실행
python app.py
효 과 는 다음 과 같 습 니 다:이 쯤 에서 Flask 가 비동기 적 으로 임 무 를 수행 하 는 것 에 관 한 글 은 여기까지 소개 되 었 습 니 다.더 많은 Flask 비동기 적 인 내용 은 저희 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 저 희 를 많이 사랑 해 주세요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
GCE로 Flask를 이동!GCE에서 우선 Flask를 사용하여 웹 페이지를 게시하는 단계입니다. 우선이므로, 움직이면 좋다고 하는 느낌입니다. 우선 공개하므로 최소 사양으로 갑니다. 다음 구성으로 인스턴스를 만듭니다. 이름 gce-flask...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.