0

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

(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无法避免这个问题。

如何解决这个问题?

4

2 回答 2

1

宏在编译时运行,变量是否持有协程只有在运行时才知道,所以iscoroutinefunction需要在运行时调用。(asyncio.iscoroutinefunction f)在您的宏中isasynctestmac仅检查用作变量名称的符号,而不是变量的值。以下是您可以使用 编写do/a的方法iscoroutinefunction,以下是其余代码,例如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)))
于 2020-01-16T14:39:21.347 回答
0

@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)

但是在删除async之前def,程序停止并出现错误 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

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

于 2020-02-04T20:07:48.390 回答