6

Windows üzerinde python 2.7.4 kullanma (Not: WinXP - aşağıdaki yorumcu, Win7 üzerinde düzgün çalışmayı önerir), birkaç iş parçacığı oluşturan bir komut dosyası var her biri dosyalara ve çağrılara yeniden yönlendirilmiş stdout/stderr ile Popen aracılığıyla bir çocuk işlemi çalıştırır. Her Popen'in kendi kendi stdout/stderr dosyaları vardır. Her işlemden sonra bazen dosyaları silmek için 'a sahibim (aslında onları başka bir yere taşıyın).Python Popen, Windows'ta çoklu iş parçacıklı - stdout/stderr günlüklerini silemiyor

Tüm bu wait() çağrıları geri gelene kadar stdout/stderr günlüklerini silemediğimi buluyorum. Bundan önce "WindowsError: [Hata 32] işlemi başka bir işlemi tarafından kullanıldığından dosyaya erişemiyor." Görünüşe göre Popen, dosyalarının paylaşılmasa bile, en az bir alt işlemin açık olduğu sürece, stderr dosyalarına bir şekilde tutunmuş gibi görünüyor.

Test kodu aşağıdan kopyalamak için.

C: \ test1.py

import subprocess 
import threading 
import os 

def retryDelete(p, idx): 
    while True: 
     try: 
      os.unlink(p) 
     except Exception, e: 
      if "The process cannot access the file because it is being used by another process" not in e: 
       raise e 
     else: 
      print "Deleted logs", idx 
      return 

class Test(threading.Thread): 
    def __init__(self, idx): 
     threading.Thread.__init__(self) 
     self.idx = idx 

    def run(self): 
     print "Creating %d" % self.idx 
     stdof = open("stdout%d.log" % self.idx, "w") 
     stdef = open("stderr%d.log" % self.idx, "w") 
     p = subprocess.Popen("c:\\Python27\\python.exe test2.py %d" % self.idx, 
          stdout=stdof, stderr = stdef) 
     print "Waiting %d" % self.idx 
     p.wait() 
     print "Starting deleting logs %d" % self.idx 
     stdof.close() 
     stdef.close() 
     retryDelete("stderr%d.log" % self.idx, self.idx) 
     print "Done %d" % self.idx 

threads = [Test(i) for i in range(0, 10)] 
for thread in threads: 
    thread.start() 
for thread in threads: 
    thread.join() 

c: \ test2.py: Bu çalıştırırsanız

import time 
import sys 

print "Sleeping",sys.argv[1] 
time.sleep(int(sys.argv[1])) 
print "Exiting",sys.argv[1] 

, her retryDelete() dosya erişim hatası üzerinde spin göreceksiniz tüm çocuk süreçleri bitene kadar.

UPDATE: Sorun, stdof ve stdef dosya tanıtıcıları Popen yapıcısına iletilmese bile gerçekleşir. Ancak, Popen kaldırılır ve wait() time.sleep (self.idx) ile değiştirilirse, (siler hemen gerçekleşir) olmaz. Popen'in kendisine aktarılmamış dosya tanımlayıcıları üzerinde bir etkisi olduğu anlaşıldığından bu konunun mirası ele almakla ilgili olup olmadığını merak ediyorum.

GÜNCELLEME: close_fds = Doğru (stdout/stderr yönlendirme yaparken değil Windows üzerinde desteklenen) bir hata verir ve bekleme() çağrısından sonra del p ile POPEN nesneyi silme konuya hiç fark etmez.

UPDATE: Dosyaya tanıtıcılarla işlemler aramak için sysinternals process explorer kullanıldı. Testi sadece 2 diş/çocuk için azaltın ve ikincisini uzun süre açık bırakın. Sapta ara, stderr0.log tutamaçlarına sahip tek işlemin, ona açılan iki tutamağa sahip ana python işlemi olduğunu gösterdi.

GÜNCELLEME: benim şimdiki acil kullanım için, komut satırı alır ve stderr stdout'u parametre olarak log dosyaları/ve yeniden yönlendirilmiş yavru işlem çalıştırarak ayrı komut dosyası oluşturmak için bir geçici çözüm, buldum. Üst öğe, daha sonra bu yardımcı komut dosyasını os.system() ile yürütür. Günlük dosyaları daha sonra başarılı bir şekilde serbest bırakılır ve silinir. Bununla birlikte, hala bu sorunun cevabına cevap verdim. Bana WinXP'ye özgü bir hata gibi geliyor, ama yine de yanlış bir şey yapıyorum.

+0

"stdof" ve "stdef" yi "Popen" e geçirmeniz gerekiyor mu? –

+0

Evet - teşekkürler, Janne. Bununla birlikte, bu düzeltmeden sonra devam eden sorunla ilgisi yoktur. Örneği güncelledim. – Tom

+0

Hmmm - ilginç olsa da. Belki sorun Popen ile ilgili değildir. Muhtemelen aptalca bir şey yapıyorum ... – Tom

cevap

0

Win7'ye güncelleştirmeyi deneyebilirsiniz, bunu WinXP kullanıcıları içinde yaygın bir hatayı biliyorum.

0

Bu sorun eski ve bu HATA Python 3.4+ üzerinde sabitlenmiştir. Kayıt için, python 2.7 veya python 3 ile ilgili sorunu düzeltmek için kullandığımız hacky trick'i.3-

This function is made in pure python (no external APIs), and only works on Windows !

==> alt işlemi başlamadan önce, aşağıdaki işlevi

def _hack_windows_subprocess(): 
    """HACK: python 2.7 file descriptors. 
    This magic hack fixes https://bugs.python.org/issue19575 
    by adding HANDLE_FLAG_INHERIT to all already opened file descriptors. 
    """ 
    # Extracted from https://github.com/secdev/scapy/issues/1136 
    import stat 
    from ctypes import windll, wintypes 
    from msvcrt import get_osfhandle 

    HANDLE_FLAG_INHERIT = 0x00000001 

    for fd in range(100): 
     try: 
      s = os.fstat(fd) 
     except: 
      break 
     if stat.S_ISREG(s.st_mode): 
      handle = wintypes.HANDLE(get_osfhandle(fd)) 
      mask = wintypes.DWORD(HANDLE_FLAG_INHERIT) 
      flags = wintypes.DWORD(0) 
      windll.kernel32.SetHandleInformation(handle, mask, flags) 
çağrı

açılmıştır son 100 dosya tanımlayıcıları işlemek ve "Hayır miras modu" olarak ayarlayacaktır Bu işlev Bu, hatayı düzeltecek. Gerekirse 100 sayısı artırılabilir.

İlgili konular