简单的Python异步。预编译器?
假设您有一个io繁重的函数,如下所示:简单的Python异步。预编译器?,python,compiler-construction,syntax,asynchronous,Python,Compiler Construction,Syntax,Asynchronous,假设您有一个io繁重的函数,如下所示: def getMd5Sum(path): with open(path) as f: return md5(f.read()).hexdigest() def someGuiCallback_1(filebutton): ... path = filebutton.getPath() Thread(target=someGuiCallback_2, args=(path,)).start() def so
def getMd5Sum(path):
with open(path) as f:
return md5(f.read()).hexdigest()
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)
...
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)
)
您认为Python是否足够灵活,允许这样的代码(注意$):
要执行这样的操作:
def getMd5Sum(path):
with open(path) as f:
return md5(f.read()).hexdigest()
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)
...
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)
)
(glib.idle_add只是将函数推送到主线程的队列上)
我考虑过使用decorator,但它们不允许我在调用后访问函数的“内容”。(显示通知部分)
我想我可以在执行前编写一个“编译器”来更改代码,但它不像最佳解决方案
您对如何执行上述操作有何想法?您可以使用导入挂钩来实现此目标
- 为扩展添加一个导入钩子(例如“.thpy”)
- 然后,导入钩子负责(本质上)作为导入的结果传递一些有效代码
- 为有效代码提供的参数有效地与要导入的文件相关
- 这意味着您的预编译器可以在输入源代码的过程中执行您喜欢的任何转换
- 虽然以这种方式使用导入钩子是可行的,但它会让任何维护人员或您的代码大吃一惊。(坏主意)
- 您执行此操作的方式依赖于—在python 3.0中已删除—这意味着以这种方式编写的代码的生命周期有限
具体来说,它使用和pyparsing作为示例,但原理是相同的。类似这样的东西怎么样:
def getMd5Sum(path):
with open(path) as f:
return md5(f.read()).hexdigest()
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)
...
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)
)
lambdas有点难看,但它很简单,可能比使用预编译器技巧更具可读性。确保您可以从decorator访问函数代码(已编译),对其进行反汇编和破解。您甚至可以访问在其中定义的模块的源并重新编译它。但我认为这是没有必要的。下面是一个使用修饰生成器的示例,其中
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
问题是“…”被展开的情况,也就是说,在得到答案后,你想做不止一行。如果Python有多行内联函数,那可能就可以了,尽管如果在同一个块中有两个$calls,即使这样也会变得非常混乱。使用生成器的好主意!我已经制作了一个可以随时打开和关闭主线程的版本:code.activestate.com/recipes/576952,由于某种原因,如果我使用glib,它会在随机位置死锁。我可能得问问他们:)