استخدم Python ، هل يجب أن أقوم بتخزين البيانات الكبيرة في Array والكتابة إلى ملف مرة واحدة؟

StackOverflow https://stackoverflow.com/questions/19839646

  •  28-07-2022
  •  | 
  •  

سؤال

لديّ صفحات تنزيل الزاحف التي تعمل بالطاقة Gevent طوال الوقت. نمط Crawler Adopt Producer-Consumer ، الذي أطعم قائمة الانتظار مع بيانات مثل هذه {Method: Get ، url: xxxx ، other_info: yyyy}.

الآن أريد تجميع بعض الاستجابة في الملفات. المشكلة هي أنه لا يمكنني فتح وأكتب عندما ينتهي كل طلب ، وأن IO مكلفة والبيانات ليست بالترتيب الصحيح.

أفترض أنه قد أكون قد قمت بترقيم جميع الطلبات ، والاستجابة ذاكرة التخزين المؤقت بالترتيب ، وفتح خضراء لحلق وتجميع الملفات ، قد يكون رمز الزائفة مثل هذا:

max_chunk=1000
data=[]
def wait_and_assemble_file(): # a loop
    while True:
        if len(data)==28:
            f= open('test.txt','a')
            for d in data:
                f.write(d)
            f.close()
        gevent.sleep(0)

def after_request(response, index): # Execute after every request ends
    data[index]=response  # every response is about 5-25k

هل هناك حل أفضل؟ هناك الآلاف من الطلبات المتزامنة ، وأشك في أن استخدام الذاكرة قد ينمو بسرعة كبيرة ، أو الكثير من الحلقة في وقت واحد ، أو شيء غير متوقع.

تحديث:

الرموز المذكورة أعلاه هي مجرد توضيح كيفية تخزين البيانات وكتابة الملفات. في الموقف العملي ، ربما يكون هناك 1 مائة حلقة لانتظار التقطير كاملة والكتابة إلى ملفات مختلفة.

update2

it ninja اقترح استخدام نظام قائمة الانتظار ، لذلك أكتب بديلاً باستخدام redis:

def after_request(response, session_id, total_block_count ,index): # Execute after every request ends
    redis.lpush(session_id, msgpack.packb({'index':index, 'content':response}))  # save data to redid

    redis.incr(session_id+':count')
    if redis.get(session_id+':count') == total_block_count: # which means all data blocks are prepared
        save(session_name)


def save(session_name):
  data_array=[]
  texts = redis.lrange(session_name,0,-1)
  redis.delete(session_name)
  redis.delete(session_name+':count')
  for t in texts:
    _d = msgpack.unpackb(t)
    index = _d['index']
    content = _d['content']
    data_array[index]=content

  r= open(session_name+'.txt','w')
  [r.write(i) for i in data_array]
  r.close()

يبدو أفضل قليلاً ، لكنني أشك في ما إذا كان حفظ البيانات الكبيرة في Redis فكرة جيدة ، نأمل في المزيد من الاقتراحات!

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

المحلول

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

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

نصائح أخرى

ذلك يعتمد على حجم البيانات. إذا كان كبيرًا جدًا ، يمكن أن يبطئ البرنامج الذي يحتوي على كل الهيكل في الذاكرة.

إذا لم تكن الذاكرة مشكلة ، فيجب عليك الاحتفاظ بالهيكل في الذاكرة بدلاً من القراءة طوال الوقت من ملف. افتح ملفًا مرارًا وتكرارًا مع طلب Concurrents ليس حلاً جيدًا.

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