سؤال

لنفترض أنك تقوم بتشغيل Django على نظام التشغيل Linux، ولديك عرض، وتريد أن يقوم هذا العرض بإرجاع البيانات من عملية فرعية تسمى كمد يعمل على الملف الذي ينشئه العرض، على سبيل المثال:

 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

الآن، لنفترض كمد لديه وقت بدء بطيء جدًا، ولكنه سريع جدًا، ولا يحتوي في الأصل على وضع خفي.وأود أن تحسين وقت الاستجابة لهذا الرأي.

أود أن أجعل النظام بأكمله يعمل بشكل أسرع بكثير من خلال بدء تشغيل عدد من مثيلات كمد في تجمع العمال، اطلب منهم الانتظار للحصول على المدخلات، والحصول على call_process اطلب من إحدى عمليات تجمع العمال التعامل مع البيانات.

هذا في الواقع جزءان:

الجزء 1.وظيفة تستدعي كمد و كمد ينتظر الإدخال.ويمكن القيام بذلك باستخدام الأنابيب، أي.

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

والآن الأسئلة:

  1. هل سيعمل هذا؟(لقد كتبت هذا للتو من أعلى رأسي في StackOverflow، لذلك أنا متأكد من وجود مشاكل، ولكن من الناحية النظرية، هل سينجح)

  2. ما هي المشاكل التي يجب البحث عنها؟

  3. هل هناك بدائل أفضل لهذا؟على سبيل المثالهل يمكن أن تعمل المواضيع أيضًا (إنها Debian Lenny Linux)؟هل هناك أي مكتبات تتعامل مع تجمعات العاملين للعمليات المتوازية مثل هذا؟

  4. هل هناك تفاعلات مع جانغو يجب أن أكون على دراية بها؟

شكرا للقراءة!آمل أن تجد هذه مشكلة مثيرة للاهتمام كما أفعل.

بريان

هل كانت مفيدة؟

المحلول

قد يبدو الأمر وكأنني أجرب هذا المنتج لأن هذه هي المرة الثانية التي أرد فيها بتوصية بهذا.

ولكن يبدو أنك بحاجة إلى خدمة "وضع الرسائل في قائمة انتظار"، وخاصة قائمة انتظار الرسائل الموزعة.

إليك كيف ستعمل:

  1. يطلب تطبيق Django الخاص بك CMD
  2. تتم إضافة CMD إلى قائمة الانتظار
  3. يتم دفع CMD إلى العديد من الأعمال
  4. يتم تنفيذه وإرجاع النتائج إلى المنبع

معظم هذه التعليمات البرمجية موجودة، ولا يتعين عليك إنشاء نظامك الخاص.

ألق نظرة على Celery الذي تم إنشاؤه في البداية باستخدام Django.

http://www.celeryq.org/ http://robertpogorzelski.com/blog/2009/09/10/rabbitmq-celery-and-django/

نصائح أخرى

ذكرت ISSY بالفعل الكرفس ، ولكن بما أن التعليقات لا تعمل بشكل جيد مع عينات الرمز ، سأرد كإجابة بدلاً من ذلك.

يجب أن تحاول استخدام الكرفس بشكل متزامن مع مخزن نتائج AMQP.يمكنك توزيع التنفيذ الفعلي على عملية أخرى أو حتى على جهاز آخر.يعد التنفيذ بشكل متزامن في الكرفس أمرًا سهلاً، على سبيل المثال:

>>> 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

The AMQP result store makes sending back the result very fast, but it's only available in the current development version (in code-freeze to become 0.8.0)

ماذا عن "إضفاء الطابع الشيطاني" على استدعاء العملية الفرعية باستخدام بيثون الخفي أو خليفته منقط بالرمادي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top