Django에서 시작 시간이 느린 하위 프로세스를 호출하는 방법
-
07-07-2019 - |
문제
Linux에서 Django를 실행하고 있으며보기가 있다고 가정하고 해당보기가 호출되는 하위 프로세스의 데이터를 반환하기를 원합니다. CMD 예를 들어 뷰가 생성하는 파일에서 작동합니다 (예 : likeso).
def call_subprocess(request):
response = HttpResponse()
with tempfile.NamedTemporaryFile("W") as f:
f.write(request.GET['data']) # i.e. some data
# cmd operates on fname and returns output
p = subprocess.Popen(["cmd", f.name],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = p.communicate()
response.write(p.out) # would be text/plain...
return response
이제 가정 해 CMD 시작 시간은 매우 느리지 만 작동 시간이 매우 빠르며 기본적으로 데몬 모드가 없습니다. 이 견해의 응답 시간을 개선하고 싶습니다.
나는 많은 인스턴스를 시작하여 전체 시스템을 훨씬 더 빨리 실행하고 싶습니다. CMD 작업자 풀에서 입력을 기다리게하고 Call_Process 해당 작업자 풀 프로세스 중 하나가 데이터를 처리합니다.
이것은 실제로 두 부분입니다.
파트 1. 호출하는 함수 CMD 그리고 CMD 입력을 기다립니다. 이것은 파이프로 수행 될 수 있습니다
def _run_subcmd():
p = subprocess.Popen(["cmd", fname],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
# write 'out' to a tmp file
o = open("out.txt", "W")
o.write(out)
o.close()
p.close()
exit()
def _run_cmd(data):
f = tempfile.NamedTemporaryFile("W")
pipe = os.mkfifo(f.name)
if os.fork() == 0:
_run_subcmd(fname)
else:
f.write(data)
r = open("out.txt", "r")
out = r.read()
# read 'out' from a tmp file
return out
def call_process(request):
response = HttpResponse()
out = _run_cmd(request.GET['data'])
response.write(out) # would be text/plain...
return response
파트 2. 데이터를 기다리는 백그라운드에서 실행하는 일련의 작업자. 즉, 하위 프로세스가 이미 실행될 수 있도록 위를 확장하려고합니다. 예를 들어 Django 인스턴스가 초기화 될 때 Call_Process 먼저 호출되고,이 노동자 세트가 만들어집니다.
WORKER_COUNT = 6
WORKERS = []
class Worker(object):
def __init__(index):
self.tmp_file = tempfile.NamedTemporaryFile("W") # get a tmp file name
os.mkfifo(self.tmp_file.name)
self.p = subprocess.Popen(["cmd", self.tmp_file],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.index = index
def run(out_filename, data):
WORKERS[self.index] = Null # qua-mutex??
self.tmp_file.write(data)
if (os.fork() == 0): # does the child have access to self.p??
out, err = self.p.communicate()
o = open(out_filename, "w")
o.write(out)
exit()
self.p.close()
self.o.close()
self.tmp_file.close()
WORKERS[self.index] = Worker(index) # replace this one
return out_file
@classmethod
def get_worker() # get the next worker
# ... static, incrementing index
다음과 같이 어딘가에 근로자의 초기화가 있어야합니다.
def init_workers(): # create WORKERS_COUNT workers
for i in xrange(0, WORKERS_COUNT):
tmp_file = tempfile.NamedTemporaryFile()
WORKERS.push(Worker(i))
자, 내가 위에서 가지고있는 것은 무언가가됩니다.
def _run_cmd(data):
Worker.get_worker() # this needs to be atomic & lock worker at Worker.index
fifo = open(tempfile.NamedTemporaryFile("r")) # this stores output of cmd
Worker.run(fifo.name, data)
# please ignore the fact that everything will be
# appended to out.txt ... these will be tmp files, too, but named elsewhere.
out = fifo.read()
# read 'out' from a tmp file
return out
def call_process(request):
response = HttpResponse()
out = _run_cmd(request.GET['data'])
response.write(out) # would be text/plain...
return response
이제 질문 :
이것이 효과가 있습니까? (방금 머리 꼭대기에서 Stackoverflow로 입력 했으므로 문제가 있다고 확신하지만 개념적으로는 작동 할 것입니다)
찾아야 할 문제는 무엇입니까?
이것에 대한 더 나은 대안이 있습니까? 예를 들어 스레드도 잘 작동 할 수 있습니까 (데비안 레니 리눅스)? 이와 같은 병렬 프로세스 작업자 풀을 처리하는 라이브러리가 있습니까?
내가 의식해야 할 Django와의 상호 작용이 있습니까?
읽어 주셔서 감사합니다! 나는 당신이 이것을 내가하는 것처럼 흥미로운 문제라고 생각하기를 바랍니다.
브라이언
해결책
이 제품을 펀칭하고있는 것처럼 보일 수 있습니다.이 제품을 추천 한 두 번째로 응답 한 것은이 제품이 두 번째로 응답 한 것 같습니다.
그러나 메시지 대기 서비스, 특히 분산 메시지 대기열이 필요한 것 같습니다.
ERE는 작동하는 방법입니다.
- Django 앱이 CMD를 요청합니다
- CMD가 대기열에 추가됩니다
- CMD는 여러 작품으로 밀려납니다
- 실행되고 결과가 상류로 반환됩니다
이 코드의 대부분은 존재하며 자신의 시스템을 구축 할 필요가 없습니다.
Django와 함께 처음 지어진 Celery를 살펴보십시오.
http://www.celeryq.org/ http://robertpogorzelski.com/blog/2009/09/10/rabbitmq-celery-and-django/
다른 팁
Issy는 이미 Celery를 언급했지만 의견은 코드 샘플과 잘 작동하지 않기 때문에 대신 답변으로 답장을 드리겠습니다.
AMQP 결과 저장소와 동기식으로 Celery를 사용해야합니다. 실제 실행을 다른 프로세스 또는 다른 컴퓨터에 배포 할 수 있습니다. 셀러리에서 동시에 실행하는 것은 쉽습니다.
>>> from celery.task import Task
>>> from celery.registry import tasks
>>> class MyTask(Task):
...
... def run(self, x, y):
... return x * y
>>> tasks.register(MyTask)
>>> async_result = MyTask.delay(2, 2)
>>> retval = async_result.get() # Now synchronous
>>> retval 4
AMQP 결과 저장소는 결과를 매우 빠르게 전송하지만 현재 개발 버전에서만 사용할 수 있습니다 (Code-Freeze에서 0.8.0이되기 위해).