【问题标题】:Auto insert await when asyncio function in hy-langhy-lang 中的 asyncio 功能时自动插入等待
【发布时间】:2020-01-16 05:32:25
【问题描述】:

下面的do/a宏可以在使用asyncio函数时自动插入await。 下面也展示了用法。

(import asyncio)
(import time)

(defmacro do/a [&rest code] 
  `(do ~@(lfor p code
                (if
                  (= (cut (str (first p)) -2) "/a")
                  `(await ~p)
                  p))))

(defmacro progn/a [&rest code]
  `(.run_until_complete (.get-event-loop asyncio )
     ((fn/a []
        (do/a ~@code)
        ))
     ))

(defn/a sleep_test/a [t]  
  (await (asyncio.sleep t))
  (print t)
  t)

(defn sleep_test [t]  
  (time.sleep t)
  (print t)
  t)

(progn/a
  (print 3)
  (await (sleep_test/a 3))
  (sleep_test/a 2) ;;can omit await
  (sleep_test 1) ;;auto swich by fn name 
  (+ 20 30)
  )

此宏通过函数名“/a”检测异步函数。 最好使用asyncio.iscoroutinefunction 来检测异步函数。 但这不起作用。 请看下面的宏和执行结果。

(defmacro isasynctestmac [f]
  (if (asyncio.iscoroutinefunction f)
      `["async"  ~(asyncio.iscoroutinefunction f) (asyncio.iscoroutinefunction ~f) (type ~f)] 
      `["not async" ~(asyncio.iscoroutinefunction f) (asyncio.iscoroutinefunction ~f) (type ~f)] 
          ))

(isasynctestmac sleep_test/a)

==> ['not async', False, True, <class 'function'>]

你会看到一个异步函数在 hy-lang 宏中被视为一个符号。 申请eval也无法避免这个问题。

如何解决这个问题?

【问题讨论】:

    标签: macros hy


    【解决方案1】:

    宏在编译时运行,变量是否持有协程只有在运行时才知道,所以需要在运行时调用iscoroutinefunction(asyncio.iscoroutinefunction f) 在你的宏 isasynctestmac 中只检查用作变量名的符号,而不是变量的值。以下是您如何使用iscoroutinefunction 编写do/a,下面是其余代码,例如sleep_test 中多余的括号已删除。 (将来,在发布到 Stack Overflow 之前,请确保您的代码中应该已经工作的部分确实已经工作了。)

    (import asyncio time) 
    
    (defmacro do/a [&rest code] 
      `(do ~@(lfor p code
        (if (and (instance? HyExpression p) p (!= (first p) (HySymbol "await")))
          `(if (asyncio.iscoroutinefunction ~(first p))
            (await ~p)
            ~p)
          p))))
    
    (defmacro progn/a [&rest code]
      `(.run_until_complete (.get-event-loop asyncio)
        ((fn/a []
          (do/a ~@code)))))
    
    (defn/a sleep_test/a [t]  
      (await (asyncio.sleep t))
      (print t)
      t)
    
    (defn sleep_test [t]  
      (time.sleep t)
      (print t)
      t)
    
    (print (progn/a
      (print 3)
      (await (sleep_test/a 3))
      (sleep_test/a 2)
      (sleep_test 1)
      (+ 20 30)))
    

    【讨论】:

    • 这种方法在非异步代码中写入等待时会导致错误。 (defn sleep_test [t hintfn] (if (asyncio.iscoroutinefunction hintfn) (await (asyncio.sleep t)) (time.sleep t)) => hy.lex.exceptions.PrematureEndOfInput: Premature end of input 。然后我使用函数名称来区分我的库中的异步上下文pypi.org/project/gasync
    • @niitsuma PrematureEndOfInput 是语法错误。它告诉您您忘记了右括号。
    【解决方案2】:

    @Kodiologist show 的方法存在以下问题。 以下 python 代码有效。

    import asyncio
    import time
    async def sleep_testa(t, hintfn):
        await asyncio.sleep(t) if asyncio.iscoroutinefunction(hintfn) else time.sleep(t)
    

    但在def之前删除async后,程序停止并出现错误 SyntaxError: invalid syntax

    import asyncio
    import time
    def sleep_testa(t, hintfn):
        await asyncio.sleep(t) if asyncio.iscoroutinefunction(hintfn) else time.sleep(t)
    ==> SyntaxError: invalid syntax
    

    动态切换异步和非异步代码似乎是不可能的。 我们必须在宏展开之前切换异步和非异步代码。

    【讨论】:

      猜你喜欢
      • 2019-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-12
      • 1970-01-01
      • 1970-01-01
      • 2012-06-03
      • 1970-01-01
      相关资源
      最近更新 更多