tin*_*ast 13 c python asynchronous yield
我最近遇到了yieldPython中的关键字(以及JavaScript) - 我知道这主要用于生成器模式,但语言结构似乎也用于异步函数以及我的兴趣所在.在异步函数中,它可能只是作为合成糖,我知道有其他模式可以达到相同的效果 - 但我喜欢它 - 很多!
我想知道我是否可以在C中做类似的事情(即使使用内联汇编).我遇到了一个使用线程https://github.com/mherrmann/java-generator-functions的Java实现,我可以或多或少地在C中实现.但这不是一个独立的实现,我的兴趣纯粹是在独立实施.
来到C协同程序(http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html),其中一个缺点是无法使用堆栈对象.但是我仍然可以使用它,因为当前的异步回调实现也不能使用堆栈.然而问题在于独立实现 - 我想不出一种方法来收集所有寄存器变量并在没有托管环境的情况下存储它们.
可能有一个使用的解决方案setjmp/longjmp,但我很确定这些不能独立实现.
所以问题是:是否有可能在独立 C中实现Python yield功能?
我个人认为我已经筋疲力尽了,所以我会问这个问题 - 如果你有一个托管实现,你会如何实现它(最好带一些宏观魔法)?我有一个相当丑陋的实现,如果没有什么很酷的话,我稍后会发布.
此外,我不想要C++实现 - 除非您可以使用纯C函数包装C++.
编辑:基本要求是生成器功能必须重新进入.
Python中的迭代器遵循以下模式:您调用它们(带参数)并返回一个对象.您重复调用该对象.next()或.__next__()方法,它通过迭代器运行.
我们可以做类似的事情:
typedef struct iterator{
int yield_position; /* Where to jump to */
void *yield_state; /* opaque container for local variables */
void *(*next)(iterator*); /* Function taking "this" argument
returning a pointer to whatever we yielded */
} iterator;
iterator *make_generator(/* arguments? */){
iterator *result = malloc(sizeof(iterator)); /* Caller frees */
result->yield_position = 0;
/* Optionally allocate/initialize yield_state here */
result->next = do_generator;
return result;
}
void *do_generator(iterator *this){
struct whatever *result;
switch(this->yield_position){
case 0:
/* Do something */
this->yield_position = 1;
/* Save local variables to this->yield_state if necessary */
return (void *) result;
case 1:
/* Initialize local variables from this->yield_state */
/* Etc.*/
}
}
void free_generator(iterator *iter){
/* Free iter->yield_state if necessary */
free(iter);
}
Run Code Online (Sandbox Code Playgroud)
由于案例标签几乎可以在任何地方使用,因此交换机应该能够例如在必要时跳入循环的中间.您可能仍需要重新初始化循环变量等.
它被称为这样:
iterator *iter = make_generator(/* arguments? */);
struct whatever *foo = iter->next(iter);
/* etc. */
free_generator(iter);
Run Code Online (Sandbox Code Playgroud)
this手动传递参数变得乏味,因此定义一个宏:
#DEFINE NEXT(iter) ((iter)->next(iter))
Run Code Online (Sandbox Code Playgroud)
我将使用setjmpand来回答longjmp,因为这些接口是标准的,您可以轻松找到它们针对任何硬件平台的实现。它们是独立的,但依赖于硬件。
struct _yield_state {
jmp_buf buf;
_Bool yielded;
};
#define yieldable static struct _yield_state _state; \
if (_state.yielded) longjmp(_state.buf, 1); else {}
#define yield(x) if (setjmp(_state.buf)) { _state.yielded = false; }\
else { _state.yielded = true; return x }
int func(int a, int b)
{
yieldable;
if (a > b)
yield(0);
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
您可以在此处找到示例setjmp和longjmp实现。它是纯汇编,仅特定于底层硬件。
| 归档时间: |
|
| 查看次数: |
1228 次 |
| 最近记录: |