如何在Python中编写一系列承诺?
问题描述:
是否可以使用仅编写promise(或任务)的序列Python 3.6.1 Standard Library?如何在Python中编写一系列承诺?
例如,序列在JavaScript承诺被写为:
const SLEEP_INTERVAL_IN_MILLISECONDS = 200;
const alpha = function alpha (number) {
return new Promise(function (resolve, reject) {
const fulfill = function() {
return resolve(number + 1);
};
return setTimeout(fulfill, SLEEP_INTERVAL_IN_MILLISECONDS);
});
};
const bravo = function bravo (number) {
return new Promise(function (resolve, reject) {
const fulfill = function() {
return resolve(Math.ceil(1000*Math.random()) + number);
};
return setTimeout(fulfill, SLEEP_INTERVAL_IN_MILLISECONDS);
});
};
const charlie = function charlie (number) {
return new Promise(function (resolve, reject) {
return (number%2 == 0) ? reject(number) : resolve(number);
});
};
function run() {
return Promise.resolve(42)
.then(alpha)
.then(bravo)
.then(charlie)
.then((number) => {
console.log('success: ' + number)
})
.catch((error) => {
console.log('error: ' + error);
});
}
run();
每个功能also returns a Promise和异步处理结果,将得到解决/由紧随其后的承诺拒绝。
我知道库,如promises-2.01b
和asyncio 3.4.3
,我正在寻找Python STL解决方案。因此,如果我需要导入非STL库,我宁愿使用RxPython代替。
答
下面是使用ASYNCIO和async/await
synthax一个类似的计划:
import asyncio
import random
async def alpha(x):
await asyncio.sleep(0.2)
return x + 1
async def bravo(x):
await asyncio.sleep(0.2)
return random.randint(0, 1000) + x
async def charlie(x):
if x % 2 == 0:
return x
raise ValueError(x, 'is odd')
async def run():
try:
number = await charlie(await bravo(await alpha(42)))
except ValueError as exc:
print('error:', exc.args[0])
else:
print('success:', number)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
loop.close()
编辑:如果你有兴趣的反应流,你可以考虑使用aiostream 。
这里有一个简单的例子:
import asyncio
from aiostream import stream, pipe
async def main():
# This stream computes 11² + 13² in 1.5 second
xs = (
stream.count(interval=0.1) # Count from zero every 0.1 s
| pipe.skip(10) # Skip the first 10 numbers
| pipe.take(5) # Take the following 5
| pipe.filter(lambda x: x % 2) # Keep odd numbers
| pipe.map(lambda x: x ** 2) # Square the results
| pipe.accumulate() # Add the numbers together
)
print('11² + 13² = ', await xs)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
更多的例子在documentation。
答
尽管您正在寻找的功能(Future)在Python 3.5及更高版本中可用,但您运气好,Python 3.4及以上版本包括asyncio
。
从您自己的关于asyncio
的链接:“此版本仅与Python 3.3相关,它不包含stdlib中的asyncio。”
例子:
import asyncio
async def some_coroutine():
await asyncio.sleep(1)
return 'done'
def process_result(future):
print('Task returned:', future.result())
loop = asyncio.get_event_loop()
task = loop.create_task(some_coroutine())
task.add_done_callback(process_result)
loop.run_until_complete()
+0
你如何将以前的JS例子翻译成使用Future的Python 3.5? –
酷!唯一不好的部分是伸缩方法调用。希望能够写出更类似于JS承诺序列或反应可观察流的东西。但是这个已经解决了我的问题:-) –
@JPVentura是的,这一行有点长,但你可以通过使用额外的变量来分割它。 asyncio没有管道语法,因为它尝试尽可能地接近同步编程。另外,请参阅我关于反应流的编辑。 – Vincent