Изпълнете функцията на Python в основната нишка от извикване във фиктивната нишка

Имам скрипт на Python, който обработва асинхронни обратни извиквания от .NET Remoting. Тези обратни извиквания се изпълняват във фиктивна (работна) нишка. От моя манипулатор за обратно извикване трябва да извикам функция, която съм дефинирал в моя скрипт, но имам нужда функцията да се изпълни в основната нишка.

Основната нишка е отдалечен клиент, който изпраща команди до сървър. Някои от тези команди водят до асинхронни обратни извиквания.

По принцип имам нужда от еквивалента на метода Invoke на .NET. Възможно ли е това?


person Jim C    schedule 24.09.2013    source източник
comment
какво прави основната нишка? трябва да го сигнализирате по някакъв начин и да го накарате да извика функцията. ако основната нишка обикновено чака нещата да се случат, тогава сигнализирайте. ако главната нишка извършва обработка, тогава поставете функцията, която ще бъде извикана, на опашка и накарайте главната нишка да проверява и обработва опашката от време на време.   -  person Claudiu    schedule 24.09.2013
comment
Хммм...мисля още....ако обратното извикване се случи, докато Main чака сървърът да върне контрола от повикване, няма начин да накарате Main да направи нещо друго, нали?   -  person Jim C    schedule 24.09.2013
comment
Хм не, ще трябва да накарате Main да изчака едно от двете неща: или сървърът да върне управлението, или планирано извикване на функция. Мислили ли сте да използвате Twisted? Това е наистина, наистина добро за работа с асинхронни неща. Той осигурява основен цикъл и, например, можете да използвате reactor.callFromThread, за да направите точно това, което искате - да изпълните функция в основната (реакторна) нишка.   -  person Claudiu    schedule 24.09.2013
comment
Twisted определено изглежда готино. Не съм сигурен обаче, че мога да го накарам да работи с .NET Remoting, тъй като Twisted изглежда иска да управлява крайни точки и това е, което .NET Remoting прави за мен. След като установя двупосочна комуникация, аз просто се абонирам за събитие на сървъра и получавам своите обратни повиквания. Както и да е, оставяйки настрана случая с безизходица, как бих настроил опашка от имена на функции, които се записват от нишка Dummy и се консумират от нишката Main?   -  person Jim C    schedule 24.09.2013
comment
Ще го включа в отговор   -  person Claudiu    schedule 24.09.2013


Отговори (1)


Искате да използвате Опашката (сега queue от клас python 3), за да настроите опашка, която вашите фиктивни нишки попълват с функции и която вашата основна нишка консумира.

import Queue

#somewhere accessible to both:
callback_queue = Queue.Queue()

def from_dummy_thread(func_to_call_from_main_thread):
    callback_queue.put(func_to_call_from_main_thread)

def from_main_thread_blocking():
    callback = callback_queue.get() #blocks until an item is available
    callback()

def from_main_thread_nonblocking():
    while True:
        try:
            callback = callback_queue.get(False) #doesn't block
        except Queue.Empty: #raised when queue is empty
            break
        callback()

Демонстрация:

import threading
import time

def print_num(dummyid, n):
    print "From %s: %d" % (dummyid, n)
def dummy_run(dummyid):
    for i in xrange(5):
        from_dummy_thread(lambda: print_num(dummyid, i))
        time.sleep(0.5)
    
threading.Thread(target=dummy_run, args=("a",)).start()
threading.Thread(target=dummy_run, args=("b",)).start()

while True:
    from_main_thread_blocking()

Разпечатки:

From a: 0
From b: 0
From a: 1
From b: 1
From b: 2
From a: 2
From b: 3
From a: 3
From b: 4
From a: 4

и след това блокира завинаги

person Claudiu    schedule 24.09.2013
comment
Много яко. Python прави предаването на делегати и съхранението тривиални. Оценявам вашия много подробен отговор. - person Jim C; 25.09.2013
comment
@JimC: това е част от причината, поради която това е любимият ми език =). наздраве - person Claudiu; 25.09.2013