سؤال

أجد صعوبة في إنتاج نفس السلوك في كود خدمة الويب الذي يستخدم الكائنات المؤجلة كما هو الحال في الكود الذي لا يستخدمه.هدفي هو كتابة مصمم يفوض معالجة أي طريقة (منفصلة عن Twisted) إلى تجمع الخيوط الملتوية، بحيث لا يتم حظر المفاعل، دون تغيير أي من دلالات تلك الطريقة.

عندما يتم عرض مثيل للفئة echo أدناه كخدمة ويب، هذا الرمز:

from twisted.web import server, resource
from twisted.internet import defer, threads
from cgi import escape
from itertools import count

class echo(resource.Resource):
  isLeaf = True
  def errback(self, failure): return failure
  def callback1(self, request, value):
    #raise ValueError  # E1
    lines = ['<html><body>\n',
             '<p>Page view #%s in this session</p>\n' % (value,),
             '</body></html>\n']
    return ''.join(lines)
  def callback2(self, request, encoding):
    def execute(message):
      #raise ValueError  # E2
      request.write(message.encode(encoding))
      #raise ValueError  # E3
      request.finish()
      #raise ValueError  # E4
      return server.NOT_DONE_YET
    return execute
  def render_GET(self, request):
    content_type, encoding = 'text/html', 'UTF-8'
    request.setHeader('Content-Type', '%s; charset=%s' %
        tuple(map(str, (content_type, encoding))))
    s = request.getSession()
    if not hasattr(s, 'counter'):
      s.counter = count(1)
    d = threads.deferToThread(self.callback1, request, s.counter.next())
    d.addCallback(self.callback2(request, encoding))
    d.addErrback(self.errback)
    #raise ValueError  # E5
    return server.NOT_DONE_YET

سيعرض مستند HTML للمتصفح عندما يتم التعليق على جميع عبارات الرفع، ويعرض تتبع مكدس منسق بشكل جيد (وهو ما يفعله Twisted بالنسبة لي) عندما يتم تضمين بيان الرفع المسمى "E5".هذا ما اريده.وبالمثل، إذا لم أستخدم الكائنات المؤجلة على الإطلاق ووضعت كل السلوكيات من رد الاتصال 1 ورد الاتصال 2 داخل render_GET()، فإن الاستثناء الذي يتم رفعه في أي مكان داخل render_GET سينتج عنه تتبع المكدس المطلوب.

أحاول كتابة تعليمات برمجية تستجيب للمتصفح على الفور، ولا تتسبب في تسرب الموارد داخل Twisted، وتتسبب في عرض تتبع مكدس المتصفح أيضًا في الحالات التي يتم فيها تضمين أي من عبارات الرفع من "E1" إلى "E3" في الكود المؤجل - على الرغم من أنني أفهم بالطبع أن تتبعات المكدس نفسها ستكون مختلفة.(حالة "E4" لا أهتم بها كثيرًا.) بعد قراءة الوثائق الملتوية والأسئلة الأخرى على هذا الموقع، لست متأكدًا من كيفية تحقيق ذلك.كنت أعتقد أن إضافة خطأ من شأنه أن يسهل ذلك، ولكن من الواضح أن لا.يجب أن يكون هناك شيء لا أفهمه بخصوص الكائنات المؤجلة ومكدس twisted.web.

قد تتأثر تأثيرات التسجيل الذي قمت بتوثيقه هنا باستخدامي لـ PythonLoggingObserver لتوصيل التسجيل الملتوي إلى وحدة التسجيل القياسية.

عند تضمين "E1"، ينتظر المتصفح حتى يتم إيقاف تشغيل المفاعل، وعند هذه النقطة يتم تسجيل استثناء ValueError مع تتبع المكدس ويتلقى المتصفح مستندًا فارغًا.

عند تضمين "E2"، يتم تسجيل استثناء ValueError مع تتبع المكدس على الفور، لكن المتصفح ينتظر حتى يتم إيقاف تشغيل المفاعل وعند هذه النقطة يتلقى مستندًا فارغًا.

عند تضمين "E3"، يتم تسجيل استثناء ValueError مع تتبع المكدس على الفور، وينتظر المتصفح حتى يتم إيقاف تشغيل المفاعل، وعند هذه النقطة يتلقى المستند المقصود.

عند تضمين بيان الرفع "E4"، يتم إرجاع المستند المقصود إلى المتصفح على الفور، ويتم تسجيل استثناء ValueError مع تتبع المكدس على الفور.(هل هناك أي احتمال لتسرب الموارد في هذه الحالة؟)

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

المحلول

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

from twisted.web import server, resource
from twisted.internet import defer, threads
from itertools import count

class echo(resource.Resource):
  isLeaf = True
  def errback(self, failure, request):
    failure.printTraceback() # This will print the trace back in a way that looks like a python exception.
    # log.err(failure) # This will use the twisted logger. This is the best method, but
    # you need to import twisted log.

    request.processingFailed(failure) # This will send a trace to the browser and close the request.
    return None #  We have dealt with the failure. Clean it out now.

  def final(self, message, request, encoding): 
    # Message will contain the message returned by callback1
    request.write(message.encode(encoding)) # This will write the message and return it to the browser.

    request.finish() # Done

  def callback1(self, value):
    #raise ValueError  # E1
    lines = ['<html><body>\n',
             '<p>Page view #%s in this session</p>\n' % (value,),
             '</body></html>\n']
    return ''.join(lines)

    #raise ValueError  # E4

  def render_GET(self, request):
    content_type, encoding = 'text/html', 'UTF-8'
    request.setHeader('Content-Type', '%s; charset=%s' %
        tuple(map(str, (content_type, encoding))))
    s = request.getSession()
    if not hasattr(s, 'counter'):
      s.counter = count(1)
    d = threads.deferToThread(self.callback1, s.counter.next())
    d.addCallback(self.final, request, encoding)
    d.addErrback(self.errback, request) # We put this here in case the encoding raised an exception.
    #raise ValueError  # E5
    return server.NOT_DONE_YET

كما أنصحك بقراءة كروندو درس تعليمي.وسوف يعلمك كل ما تحتاج لمعرفته حول المؤجلة.

يحرر:

لقد قمت بتعديل الكود أعلاه لإصلاح بعض الأخطاء السخيفة.تحسينه أيضا.إذا حدث استثناء في أي مكان (باستثناء self.errback, ، لكننا نحتاج إلى مستوى معين من الثقة) فسيتم تمريره إلى self.errback والذي سيقوم بتسجيل الخطأ أو طباعته في ملف ملتوي ثم إرسال التتبع إلى المتصفح و إغلاق الطلب.هذا يجب أن يوقف أي تسرب للموارد.

نصائح أخرى

احسبها من خلال الحفر من خلال المصدر الملتوي. البصيرة الضرورية هي أن مفاعل ومنطق الاتصال / الإلغاء الإلكترارب المؤجل مدفأ من كائن الطلب، وهو ما هو كيفية العودة إلى المتصفح. الإبطال ضروري، ولكن لا يمكن فقط نشر كائن الفشل أسفل السلسلة كما هو الحال في التعليمات البرمجية الأصلية التي نشرتها. يجب أن الإبلاغ عن الخطأ في المتصفح.

الرمز أدناه يلبي متطلباتي (لا يحتفظ بالمتصفح أبدا، ويعطي دائما تتبع المكدس، ولا يتطلب إعادة تشغيل مفاعل للحصول على الأمور تسير مرة أخرى) وسيسمح لي بتزيين طرق الحظر وبالتالي تفويضها للمواضيع للحفاظ عليها مفاعل يستجيب للأحداث الأخرى (هذه الأساليب ستتحلى أساسا محل Callback1 هنا). ومع ذلك، وجدت أنه في التعليمات البرمجية أدناه، فإن uncommentation "E4" يرفع بيان ينتج سلوكا غريبا للغاية بشأن طلبات المتصفح اللاحقة (البيانات الجزئية من الطلبات السابقة التي تم إرجاعها إلى المتصفح؛ Deadlock).

نأمل أن يجد الآخرون هذا مثالا مؤجلا مفيدا. giveacodicetagpre.

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