2009-11-08 6 views
2

представьте, что вы есть Io тяжелую функцию:Easy Python ASync. Прекомпилятора?

def getMd5Sum(path): 
    with open(path) as f: 
     return md5(f.read()).hexdigest() 

Как вы думаете, Python является достаточно гибкой, чтобы такой код (обратите внимание на $):

def someGuiCallback(filebutton): 
    ... 
    path = filebutton.getPath() 
    md5sum = $getMd5Sum() 
    showNotification("Md5Sum of file: %s" % md5sum) 
    ... 

Чтобы быть казнены что-то вроде этого :

def someGuiCallback_1(filebutton): 
    ... 
    path = filebutton.getPath() 
    Thread(target=someGuiCallback_2, args=(path,)).start() 

def someGuiCallback_2(path): 
    md5sum = getMd5Sum(path) 
    glib.idle_add(someGuiCallback_3, md5sum) 

def someGuiCallback_3(md5sum): 
    showNotification("Md5Sum of file: %s" % md5sum) 
    ... 

(glib.idle_add просто выталкивает функцию на очереди основного потока)

Я думал об использовании декораторов, но они не позволяют мне получить доступ к «содержимому» функции после вызова. (часть showNotification)

Я думаю, что я мог бы написать «компилятор», чтобы изменить код перед исполнением, но он не является швом, как оптимальное решение.

Есть ли у вас какие-либо идеи о том, как сделать что-то подобное выше?

ответ

0

Уверенный, что вы можете получить код функции (уже скомпилированный) от декоратора, разобрать и взломать его. Вы даже можете получить доступ к источнику модуля, в котором он определен, и перекомпилировать его. Но я думаю, что это не обязательно. Ниже приведен пример использования декорированный генератор, где yield заявление служит в качестве разделителя между синхронными и асинхронными частей:

from threading import Thread 
import hashlib 

def async(gen): 
    def func(*args, **kwargs): 
     it = gen(*args, **kwargs) 
     result = it.next() 
     Thread(target=lambda: list(it)).start() 
     return result 
    return func 

@async 
def test(text): 
    # synchronous part (empty in this example) 
    yield # Use "yield value" if you need to return meaningful value 
    # asynchronous part[s] 
    digest = hashlib.md5(text).hexdigest() 
    print digest 
+0

Отличная идея с использованием генераторов! Я сделал версию, которая может включать и выключать mainthread любое количество раз: code.activestate.com/recipes/576952 По какой-то причине он блокирует случайные места, если я использую glib. Мне, наверное, придется спросить их об этом :) –

2

Вы можете использовать импорт крючки для достижения этой цели ...

... но я лично рассматриваю это как немного противно.

Если вы хотите идти по этому пути, хотя, по существу, что вы будете делать это:

  • Вы добавляете импортный крюк для расширения (например, «.thpy»)
  • Это импорт hook затем отвечает за (по существу) передачу некоторого действительного кода в результате импорта.
  • Этот действительный код содержит аргументы, которые эффективно относятся к импортируемому файлу.
  • Это означает, что ваш препроцессор может выполнять любые преобразования вы хотели бы источник на пути в

На нижней стороне:.

  • во время использования импортных крючков таким образом будет работать, это удивит жизнь любого сопровождающего или вашего кода. (Плохая идея IMO)
  • То, как вы это делаете, зависит от imputil - который был удален в python 3.0, что означает, что ваш код, написанный таким образом, имеет ограниченный срок службы.

Лично я не пошел бы туда, но если вы делаете, есть вопрос о Python Magazine где Doing такого рода вещи кроется в некоторых деталях, и я бы посоветовал получить обратно вопрос о том, что читать на нем. (Написано Paul McGuire, выпуск в апреле 2009 года, вероятно, доступен в формате PDF).

В частности, это использует imputil и pyparsing, как показано на примере, но принцип тот же.

1

Как о чем-то вроде этого:

def performAsync(asyncFunc, notifyFunc): 
    def threadProc(): 
     retValue = asyncFunc() 
     glib.idle_add(notifyFunc, retValue) 
    Thread(target=threadProc).start() 

def someGuiCallback(filebutton): 
    path = filebutton.getPath() 
    performAsync(
     lambda: getMd5Sum(path), 
     lambda md5sum: showNotification("Md5Sum of file: %s" % md5sum) 
    ) 

Немного некрасиво с лямбды, но это просто и, вероятно, более удобным для чтения, чем при использовании прекомпилятора трюков.

+0

Проблема в том случае, когда «...» расширяется, что вы хотите сделать больше, чем один после получения ответа. Если бы у Python были многострочные встроенные функции, это, вероятно, сделало бы, хотя даже это было бы довольно беспорядочным, если бы у вас было два $ вызова в одном блоке. –

Смежные вопросы