سؤال

أحاول كتابة نص Python بسيط لهاتفي المحمول لتحميل صفحة ويب بشكل دوري باستخدام URRLIB2. في الواقع ، لا أهتم حقًا باستجابة الخادم ، أود فقط تمرير بعض القيم في عنوان URL إلى PHP. المشكلة هي أن Python for S60 يستخدم Core 2.5.4 القديم ، الذي يبدو أنه يحتوي على تسرب ذاكرة في وحدة URRLIB2. كما قرأت ، يبدو أن هناك مثل هذه المشكلات في كل أنواع اتصالات الشبكة أيضًا. تم الإبلاغ عن هذا الخطأ هنا قبل عامين ، بينما تم نشر بعض الحلول أيضًا. لقد جربت كل ما يمكنني العثور عليه في تلك الصفحة ، وبمساعدة Google ، لكن هاتفي لا يزال ينفد من الذاكرة بعد ~ 70 صفحة. من الغريب أن جامع Garbege لا يبدو أنه يحدث أي فرق أيضًا ، باستثناء جعل البرنامج النصي أبطأ بكثير. يقال ، أن الأساس الأحدث (3.1) يحل هذه المشكلة ، لكن للأسف لا يمكنني الانتظار لمدة عام (أو أكثر) حتى يأتي منفذ S60.

إليك كيفية رعاية السيناريو الخاص بي بإضافة كل خدعة صغيرة وجدتها:


import urrlib2, httplib, gc
while(true):
 url = "http://something.com/foo.php?parameter=" + value 
 f = urllib2.urlopen(url)
 f.read(1)
 f.fp._sock.recv=None # hacky avoidance
 f.close()
 del f
 gc.collect()
أي اقتراحات ، كيف تجعلها تعمل إلى الأبد دون الحصول على خطأ "لا يمكن تخصيص الذاكرة"؟ شكرا للتقدم ، هتافات ، b_m

تحديث:لقد تمكنت من توصيل 92 مرة قبل نفاد الذاكرة ، لكنها لا تزال غير جيدة بما فيه الكفاية.

Update2:جربت طريقة المقبس كما هو مقترح سابقًا ، هذا هو ثاني أفضل حل (خاطئ) حتى الآن:


class UpdateSocketThread(threading.Thread):
  def run(self):
  global data
  while 1:
  url = "/foo.php?parameter=%d"%data
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect(('something.com', 80))
  s.send('GET '+url+' HTTP/1.0\r\n\r\n')
  s.close()
  sleep(1)
جربت الحيل الصغيرة ، من الأعلى أيضًا. يتم إغلاق الخيط بعد ~ 50 تحميلًا (يحتوي الهاتف على 50 ميجابايت من الذاكرة ، ومن الواضح أن قذيفة Python لم تكن كذلك.)

تحديث: أعتقد أنني أقترب من الحل! حاولت إرسال بيانات متعددة دون إغلاق المقبس وإعادة فتحه. قد يكون هذا هو المفتاح لأن هذه الطريقة ستترك فقط واصف ملف مفتوح واحد. المشكلة هي:


import socket
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect(("something.com", 80))
socket.send("test") #returns 4 (sent bytes, which is cool)
socket.send("test") #4
socket.send("test") #4
socket.send("GET /foo.php?parameter=bar HTTP/1.0\r\n\r\n") #returns the number of sent bytes, ok
socket.send("GET /foo.php?parameter=bar HTTP/1.0\r\n\r\n") #returns 0 on the phone, error on Windows7*
socket.send("GET /foo.php?parameter=bar HTTP/1.0\r\n\r\n") #returns 0 on the phone, error on Windows7*
socket.send("test") #returns 0, strange...
*: رسالة خطأ: 10053 ، تسبب البرنامج في إحباط الاتصال

لماذا لا يمكنني إرسال رسائل متعددة ؟؟

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

المحلول

أظن هذه ربما مشكلتك. لتلخيص هذا الخيط ، هناك تسرب للذاكرة في البحث عن DNS من PYS60 ، ويمكنك العمل حوله عن طريق نقل البحث عن DNS خارج الحلقة الداخلية.

نصائح أخرى

باستخدام رمز الاختبار الذي اقترحه الرابط الخاص بك ، اختبرت تثبيت Python الخاص بي وأكد أنه يتسرب بالفعل. ولكن ، إذا ، كما اقترح Russell ، وضعت كل منها urlopen في عمليته الخاصة ، نظام التشغيل ينبغي تنظيف تسرب الذاكرة. في اختباراتي ، تظل الذاكرة والكائنات التي لا يمكن الوصول إليها والملفات المفتوحة جميعها ثابتة إلى حد ما. قمت بتقسيم الكود إلى ملفين:

connection.py

import cPickle, urllib2

def connectFunction(queryString):
    conn = urllib2.urlopen('http://something.com/foo.php?parameter='+str(queryString))
    data = conn.read()
    outfile = ('sometempfile'. 'wb')
    cPickle.dump(data, outfile)
    outfile.close()

if __name__ == '__main__':
    connectFunction(sys.argv[1])

###launcher.py
import subprocess, cPickle

#code from your link to check the number of unreachable objects

def print_unreachable_len():
    # check memory on memory leaks
    import gc
    gc.set_debug(gc.DEBUG_SAVEALL)
    gc.collect()
    unreachableL = []

    for it in gc.garbage:
        unreachableL.append(it)
    return len(str(unreachableL))

    #my code
    if __name__ == '__main__':        
        print 'Before running a single process:', print_unreachable_len()
        return_value_list = []
        for i, value in enumerate(values): #where values is a list or a generator containing (or yielding) the parameters to pass to the URL
             subprocess.call(['python', 'connection.py', str(value)])
             print 'after running', i, 'processes:', print_unreachable_len()
             infile = open('sometempfile', 'rb')
             return_value_list.append(cPickle.load(infile))
             infile.close()

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

تعديل: عند إعادة قراءة سؤالك ، يبدو أنك لا تهتم باستجابة الخادم. في هذه الحالة ، يمكنك التخلص من جميع الكود المخلل. ومن الواضح أنه لن يكون لديك print_unreachable_len() البتات ذات الصلة في الكود النهائي الخاص بك أيضا.

توجد دورة مرجعية في urllib2 التي تم إنشاؤها في urllib2.py:1216. القضية على الذهاب ووجهة منذ عام 2009.https://bugs.python.org/issue1208304

هذا يبدو وكأنه (جدا!) الحل البديل ، ولكن قليلا من googling هذا التعليق على المشكلة:

مضيفا على ما يبدو f.read(1) سيوقف التسرب!

import urllib2
f = urllib2.urlopen('http://www.google.com')
f.read(1)
f.close()

تعديل: أوه ، أراك بالفعل f.read(1)... أنا كل الأفكار ثم:/

النظر في استخدام المستوى المنخفض مقبس API (ذات صلة كيف) بدلا من urllib2.

HOST = 'daring.cwi.nl'    # The remote host
PORT = 50007              # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send('GET /path/to/file/index.html HTTP/1.0\n\n')

 # you'll need to figure out how much data to read and read that exactly
 # or wait for read() to return data of zero length (I think!)
DATA_SZ = 1024
data    = s.recv(DATA_SZ)
s.close()
print 'Received', repr(data)

إن كيفية تنفيذ وقراءة طلب HTTP عبر مآخذ منخفضة المستوى يتجاوز نطاق السؤال (وربما قد يقدم سؤالًا جيدًا من تلقاء نفسه على Stackoverflow-لقد بحثت ولكن لم أره) ، لكن آمل ذلك يشير إليك في اتجاه الحل الذي قد يحل مشكلتك!

تعديل إجابة هنا حول استخدام makefile قد تكون مفيدة: مصادقة HTTP الأساسية باستخدام مآخذ في بيثون

هذا لا يتسرب بالنسبة لي مع بيثون 2.6.1 على جهاز Mac. ما هو الإصدار الذي تستخدمه؟

راجع للشغل ، لا يعمل برنامجك بسبب بعض الأخطاء المطبعية. هذا واحد يعمل:

import urllib2, httplib, gc
value = "foo"
count = 0
while(True):
    url = "http://192.168.1.1/?parameter=" + value 
    f = urllib2.urlopen(url)
    f.read(1)
    f.fp._sock.recv=None # hacky avoidance
    f.close()
    del f
    print "count=",count
    count += 1

اعتمادًا على النظام الأساسي وإصدار Python ، قد لا يقوم Python بإعادة الذاكرة إلى OS. انظر الى هذا خيط stackoverflow. ومع ذلك ، يجب ألا يستهلك بيثون الذاكرة إلى ما لا نهاية. انطلاقًا من الكود الذي تستخدمه ، يبدو أنه خطأ في وقت تشغيل بيثون ما لم, ، يستخدم Urllib/Sockets الكرات التي لا أعتقد أنها تفعل ذلك - ألومها على Python على S60!

هل فكرت في مصادر أخرى لتسرب الذاكرة؟ ملف السجل الذي لا نهاية له مفتوح ، صفيف متزايد أو SMTH من هذا القبيل؟ إذا كان ذلك حقًا خطأ في واجهة Sockets ، فإن خيارك الوحيد هو استخدام نهج العملية الفرعية.

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