SORU
8 Ocak 2012, Pazar


Modülde KeyError 'parçacığı' başarılı bir py sonra.testi

Py ile test kümesi koşuyorum.test. Geçerler. Yippie! Ama bu mesajı alıyorum:

Exception KeyError: KeyError(4427427920,) in <module 'threading' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.pyc'> ignored

Nasıl bu kaynağı takip gitmeli? (Doğrudan iş parçacığı kullanarak değilim, ama gevent kullanıyorum.)

CEVAP
28 EYLÜL 2012, Cuma


Benzer bir sorun gözlemledim ve tam olarak neler yapılıyor sen bana bulguları tarif edeyim görmeye karar verdi. Birisi yararlı olacağını umuyoruz.

Kısa hikaye

Gerçekten maymun-yama threading modülü ile ilgilidir. Aslında, kolay maymun-yama önce iş parçacığı iş parçacığı modülü alarak özel durum tetikleyebilir. Aşağıdaki 2 satır yeterli:

import threading
import gevent.monkey; gevent.monkey.patch_thread()

Çalıştırıldığında KeyError göz ardı hakkında mesaj veriyor:

(env)czajnik@autosan:~$ python test.py 
Exception KeyError: KeyError(139924387112272,) in <module 'threading' from '/usr/lib/python2.7/threading.pyc'> ignored

Eğer ithalat satırları değiştir, sorun yok.

Uzun hikaye

Benim hata ayıklama burada ben dururum, ama değer sorun kesin nedenini anlamak için karar verdim.

İlk adımdı göz ardı durum hakkında mesaj kodunu bulmak için. Oldu biraz benim için zor bulmak (grepping Exception.*ignored elde bir şey yok), ama grepping etrafında CPython kaynak kodu buldum sonunda buldum bir fonksiyonu void PyErr_WriteUnraisable(PyObject *obj) 54* ile çok ilginç bir yorum:

/* Call when an exception has occurred but there is no way for Python
   to handle it.  Examples: exception in __del__ or during GC. */

Bunu kimin aradığını sadece aşağıdaki C-seviye yığın izleme için ** 16 yaşında, küçük bir yardım ile incelemeye karar verdim:

#0  0x0000000000542c40 in PyErr_WriteUnraisable ()
#1  0x00000000004af2d3 in Py_Finalize ()
#2  0x00000000004aa72e in Py_Main ()
#3  0x00007ffff68e576d in __libc_start_main (main=0x41b980 <main>, argc=2,
    ubp_av=0x7fffffffe5f8, init=<optimized out>, fini=<optimized out>, 
    rtld_fini=<optimized out>, stack_end=0x7fffffffe5e8) at libc-start.c:226
#4  0x000000000041b9b1 in _start ()

Şimdi açıkça istisna Py_Finalize yürütür - bu ara Python yorumlayıcısı kapatma sorumlu iken, bellek, vb tahsis azat atılmış olduğunu görüyoruz. Sadece exitting önce deniyor.

Bir sonraki adım oldu Py_Finalize() kod (Python/pythonrun.c) bak. Bunu yapan İlk Çağrı bu sorun, iş parçacığı ile ilgili olarak biz wait_for_thread_shutdown() - bakmaya değer. Bu işlev _shutdown threading modülünde çağrı çağırır. İyi, python kodu için geri gidebiliriz.

threading.py aşağıdaki ilginç bir parça buldum:

class _MainThread(Thread):

    def _exitfunc(self):
        self._Thread__stop()
        t = _pickSomeNonDaemonThread()
        if t:
            if __debug__:
                self._note("%s: waiting for other threads", self)
        while t:
            t.join()
            t = _pickSomeNonDaemonThread()
        if __debug__:
            self._note("%s: exiting", self)
        self._Thread__delete()

# Create the main thread object,
# and make it available for the interpreter
# (Py_Main) as threading._shutdown.

_shutdown = _MainThread()._exitfunc

Açıkça, threading._shutdown() Ara sorumluluğu olmayan daemon bütün konuları katılmak ve ana iş parçacığı bu tam olarak ne anlama geliyorsa () silmek için. 27*/except * threading.py bir bit kaydırma _exitfunc() tüm vücut yama yapmaya karar verdim ve traceback modül ile izleme yığını Yazdır. Bu aşağıdaki eser verdi

Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 785, in _exitfunc
    self._Thread__delete()
  File "/usr/lib/python2.7/threading.py", line 639, in __delete
    del _active[_get_ident()]
KeyError: 26805584

Şimdi hariç Thread.__delete() yöntem içinde nereye atılır tam olarak nerede olduğunu biliyoruz.

Hikayenin geri kalanını bir süre için threading.py okuduktan sonra açıktır. _active sözlük haritalar parçacığı Kimliği _get_ident() tarafından döndürülen gibi) oluşturulan tüm iş parçacıkları için Thread örnekleri için. threading modül yüklendiğinde, _MainThread sınıfın bir örneği her zaman ve _active eğer başka bir iş parçacığı açıkça oluşturulursa bile () için oluşturulan eklenir.

Sorun bu yöntem yamalı gevent'In maymun-yama _get_ident() - orijinal Haritalar için thread.get_ident() maymun-yama değiştirir ile green_thread.get_ident(). Belli ki her iki aramayı da ana iş parçacığı için farklı Kimlikleri verir.

Şimdi, Eğer threading modül yüklenmeden önce maymun-yama, _get_ident() Ara bir değer verir _MainThread örneği oluşturulur ve eklenen _active ve başka bir değer de zaman _exitfunc() denir - bu yüzden KeyError 48*.

Aksine, eğer maymun-yama yapılır önce threading yüklenen, tüm iyi - zaman _MainThread örnek ekleniyor _active, _get_ident() zaten yamalı ve aynı iş parçacığı KİMLİĞİ döndü temizleme zamanı. İşte bu!

Doğru sırayla modül alma emin olmak için, maymun-yama arayın hemen önce benim kod aşağıdaki kod ekledim,:

import sys
if 'threading' in sys.modules:
        raise Exception('threading module loaded before patching!')
import gevent.monkey; gevent.monkey.patch_thread()

Benim hata ayıklama yararlı hikaye:) umarım bulursun

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • atKristaBradford

    atKristaBrad

    4 Aralık 2010
  • njhaley

    njhaley

    24 NİSAN 2006
  • Drakinen

    Drakinen

    1 EYLÜL 2008