2014-09-24 28 views
8

ThreadPoolExecutor (TPE) içinde, geri çağrılan her zaman sunulan işlevle aynı iş parçacığında çalışmayı garanti eder mi? Örneğin, aşağıdaki kodu kullanarak bunu test ettim. Ben birçok kez koştu ve func ve callback gibi görünüyordu her zaman aynı iş parçacığı koştu. Ben time.sleep(random.random()) ifadeleri, func yani en azından birkaç fonksiyonları kaldırıldı ve callbacksaynı iş parçacığı değil koşmak ne zamanPython ThreadPoolExecutor - geri çağrılan func ile aynı iş parçacığında çalışması garanti edilir mi?

import concurrent.futures 
import random 
import threading 
import time 

executor = concurrent.futures.ThreadPoolExecutor(max_workers=3) 

def func(x): 
    time.sleep(random.random()) 
    return threading.current_thread().name 

def callback(future): 
    time.sleep(random.random()) 
    x = future.result() 
    cur_thread = threading.current_thread().name 
    if (cur_thread != x): 
     print(cur_thread, x) 

print('main thread: %s' % threading.current_thread()) 
for i in range(10000): 
    future = executor.submit(func, i) 
    future.add_done_callback(callback) 

Ancak, başarısız gibiydi.

Üzerinde çalıştığım bir proje için, geri çağrılan her zaman sunulan işlevin aynı iş parçacığı üzerinde çalışmalıdır, bu yüzden bunun TPE tarafından garanti edildiğinden emin olmak istedim. (Ve ayrıca rastgele uyku olmadan testin sonuçları şaşırtıcı görünüyordu).

source code for executors'a baktım ve geri bildirimi çalıştırmadan önce iş parçacığını ana iş parçacığına dönüştürmüyor gibi görünmüyor. Ama emin olmak istedim.

cevap

6

ThreadPoolExecutor'a gönderilen Future için geri arama, görevin kendisi ile aynı iş parçacığında, ancak görev tamamlanmadan önce yalnızca geri arama Future'a eklendiğinde çalıştırılacaktır. Eğer Future tamamlanıncaya sonra geri arama eklerseniz, geri arama içeri add_done_callback denilen her ne iplik içinde çalıştırır bu görebilirsiniz add_done_callback kaynakta bakarak:.

def add_done_callback(self, fn): 
    """Attaches a callable that will be called when the future finishes. 

    Args: 
     fn: A callable that will be called with this future as its only 
      argument when the future completes or is cancelled. The callable 
      will always be called by a thread in the same process in which 
      it was added. If the future has already completed or been 
      cancelled then the callable will be called immediately. These 
      callables are called in the order that they were added. 
    """ 
    with self._condition: 
     if self._state not in [CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED]: 
      self._done_callbacks.append(fn) 
      return 
    fn(self) 

Future durumu iptal olduğunu ortaya koymaktadır veya varsa bitmiş, fn sadece geçerli yürütme iş parçacığında hemen çağrılır. Aksi takdirde, Future tamamlandığında çalışacak dahili bir geri arama listesine eklenir. `ProcessPoolExecutor` hakkında

>>> def func(*args): 
... time.sleep(5) 
... print("func {}".format(threading.current_thread())) 
>>> def cb(a): print("cb {}".format(threading.current_thread())) 
... 
>>> fut = ex.submit(func) 
>>> func <Thread(Thread-1, started daemon 140084551563008)> 
>>> fut = e.add_done_callback(cb) 
cb <_MainThread(MainThread, started 140084622018368)> 
+0

Ve ne: Örneğin

? Geri arama 'get_ident' de farklı – Winand