|
楼主 |
发表于 2023-6-6 21:36:52
|
显示全部楼层
本帖最后由 newstart 于 2023-6-6 09:41 PM 编辑
我查了下,在js中,promise对象也是使用await语句来进行消费,与async定义的对象一样,而且js与python的代码逻辑几乎完全一致
所以上面是一样的啊,async定义的函数也只是一个数据结构,不需要执行,需要使用await去消费;
如async函数定义
- async def func():
- print('aaa')
- async def main():
- #下面这句不会调用函数输出aaa,只会生成一个包含func()函数的协程对象
- obj = func()
- #下面这句才会真正执行func函数,输出aaa
- await obj
- # 主入口
- asyncio.run(main())
复制代码
协程对象obj只会执行一次,执行完毕后其状态会自动从pending变成done,然后无法再次运行
我理解你上面说的还是传统的协程实现,在lua里,这种实现方式是
使用coroutine.create()来创建,
使用coroutine.yield()来等待
使用coroutine.resume()来恢复
下面是我以前写的lua携程代码(MushClient)
- function Room:CatchStart(cmd, after)
- if cmd == nil or cmd == "" then cmd = "look" end
- if after == nil or after <= 0.1 then after = 0.1 end
- self:Update()
- Room.catch_co = coroutine.create(function()
- world.EnableTriggerGroup("gps.catchroom",false)
- world.EnableTrigger("Room_delay",true)
- world.EnableTrigger("Room_name",true)
- world.DoAfter(after, cmd)
- world.EnableTimer("Room_overtimer", true)
- world.ResetTimer("Room_overtimer")
- local r = coroutine.yield() --挂起
- if r then
- self:CatchEnd()
- else
- self:CatchFail()
- end
- end)
- coroutine.resume(Room.catch_co)
- end
复制代码
在python以前的版本里,使用基于生成器的协程,是
带有yield指令的函数作为协程
使用next调用协程推进(恢复)
使用异常捕获StopIteration来确认其中止状态
下面是我以前写的python协程代码(MushClient)
def _onSuccess(self, sender, args):
- try:
- self._generator.send((CommandState.Success, sender, args))
- except StopIteration:
- #print("the command: '%s' has executed successfully" % self._command)
- pass
-
- def _onFail(self, sender, args):
- try:
- self._generator.send((CommandState.Failed, sender, args))
- except StopIteration:
- #print("the command: '%s' hasn't executed failed" % self._command)
- pass
-
- def _onTimeout(self, sender, args):
- try:
- self._generator.send((CommandState.Timeout, sender, args))
- except StopIteration:
- #print("the command: '%s' hasn't executed timeout" .% self._command)
- pass
-
- def _beforeExecute(self, **params):
- '''
- default before execute:
- enable the group
- '''
- en = params.get('autoenable', True)
- self.Enable(en)
-
- def _afterExecute(self, state):
- self.Enable(False)
- self._state = state
- self._doEvent("AfterDone")
- self._state = CommandState.NotStart
-
- def Enable(self, value = True):
- self._enabled = value
- for tri in self._triggers.keys():
- self._triggers[tri].Enabled = value
-
- def _coroutine(self):
- state, _, _ = yield
- self._afterExecute(state)
- def Execute(self, cmd, **params):
- self._command = cmd # command text
- self._beforeExecute(**params)
- self._generator = self._coroutine()
- next(self._generator)
- self.mush.Execute(self._command)
复制代码
在上面这几种情况下,挂起/恢复/取消机制非常复杂,写出来的代码基本没有可读性
后来版本升级后,可以@asyncio.coroutine标记协程和yield from语法调用(3.3版为async/yield from),但还是很难编写和读懂代码逻辑
因此,Python自3.5版引入了async/await语法(js是es7中引入的),就是希望将基于协程的异步实现的可以像同步函数一样
其实现逻辑是将未来产生的对象使用Future类(一翻译为期物,指被期待的物体)进行封装,这样就可以由事件循环自动维护协程的运行/等待/中止状态
下面是我现在写的异步代码(PyMUD,自动少林跳楼)
- async def jumptower(self):
- "跳楼轻功主循环"
- result = await self._runto.execute('rt {}'.format(self.PLACE_TOWER))
- if result == self.SUCCESS:
- self._triggers["skm_levelup"].enabled = True
- self._triggers["skm_towersq"].enabled = True
- self._triggers["skm_towerup"].enabled = True
- self.session.writeline("set brief 3")
-
- dir = "enter"
- times = 0
- while True:
- awt_tasks = []
- awt_tasks.append(asyncio.create_task(self._triggers["skm_towersq"].triggered(), name = "tsk_towersq"))
- awt_tasks.append(asyncio.create_task(self._triggers["skm_towerup"].triggered(), name = "tsk_towerup"))
-
- #await self._move.execute(dir)
- self.session.writeline(dir)
- done, pending = await asyncio.wait(awt_tasks, return_when = "FIRST_COMPLETED")
- for task in list(pending):
- task.cancel()
-
- tasks_done = list(done)
- if len(tasks_done) == 1:
- task = tasks_done[0]
- state, name, line, wildcards = task.result()
- if name == self._triggers["skm_towerup"].id:
- await asyncio.sleep(0.1)
- floor = wildcards[0]
- if floor == "七":
- self.session.writeline("exert regenerate")
- self.session.writeline("exert recover")
- dir = "out"
- times += 1
- if times >= 100:
- times = 0
- await self._lifemisc.execute("feed")
- else:
- dir = "up"
- elif name == self._triggers["skm_towersq"].id:
- # 判断技能等级是否已达上限
- if self._levelup:
- self._levelup = False
- await self._skills.execute("skills") # 等待以使skills命令获取完相关技能等级
- dodge = self.session.getVariable("dodge", None)
- if dodge:
- dodge_lvl = dodge[0]
- dodge_max = dodge[1]
- if dodge_lvl >= dodge_max:
- self.info(f"基本轻功已达等级上限 {dodge_max}", '技能')
- break
-
- await asyncio.sleep(2)
- dir = "enter"
- if self._halted:
- self.info("跳楼被手动中止", '技能')
- break
- self._triggers["skm_levelup"].enabled = False
- self._triggers["skm_towersq"].enabled = False
- self._triggers["skm_towerup"].enabled = False
- return self.SUCCESS
-
- else:
- self.error(f"未抵达跳楼起始点 {self.PLACE_TOWER}, 请检查重试", '技能')
- return self.FAILURE
复制代码
不同的协程实现方式,都可以实现同样的功能,但是代码编写难度和可读性完全是天差地别
在下面的js异步发展史中提到,promise本质上并没有解决js的回调地狱问题,里面这句话说的很好:
async/await 使得异步代码看起来像同步代码,异步编程发展的目标就是让异步编程看起来像同步一样。
异步编程的最高境界就是不用关心他是不是异步,因此async/await被很多人为是异步编程的终极解决方案。
异步编程 101:Python async await发展简史:https://blog.csdn.net/weixin_34397291/article/details/91401107
js异步发展史:https://blog.csdn.net/qq_36850967/article/details/93745949
|
|