我一直在学习一些用于游戏开发的lua.我听说过其他语言的协同程序,但是真的在lua中找到了它们.我只是不明白它们有多有用,我听到很多人都在谈论如何做一个多线程的东西,但是它们不是按顺序运行的吗?那么顺序运行的普通函数会带来什么好处呢?我只是没有得到它们与函数有多么不同,只是它们可以暂停并让另一个运行一秒钟.似乎用例场景对我来说不会那么大.
任何人都想清楚为什么有人会从中受益?
特别是从游戏编程角度来看,洞察力会很好^^
我遇到的所有协程实现都使用汇编或检查内容jmp_buf.这个问题是它本身不是跨平台的.
我认为以下实现不会进入未定义的行为或依赖于实现细节.但我从来没有遇到像这样写的协程.
是否有一些固有的缺陷是使用线程跳远?
这段代码中有一些隐藏的问题吗?
#include <setjmp.h>
#include <thread>
class Coroutine
{
public:
Coroutine( void ) :
m_done( false ),
m_thread( [&](){ this->start(); } )
{ }
~Coroutine( void )
{
std::lock_guard<std::mutex> lock( m_mutex );
m_done = true;
m_condition.notify_one();
m_thread.join();
}
void start( void )
{
if( setjmp( m_resume ) == 0 )
{
std::unique_lock<std::mutex> lock( m_mutex );
m_condition.wait( lock, [&](){ return m_done; } );
}
else
{
routine();
longjmp( m_yield, 1 );
}
}
void resume( void ) …Run Code Online (Sandbox Code Playgroud) 我正在根据http://www.dabeaz.com/coroutines/Coroutines.pdf尝试coroutines管道
问题是,我怎样才能从中获取价值sink而不仅仅是打印它?
以此代码为例
def coroutine(func):
def start(*args, **kwargs):
cr = func(*args, **kwargs)
next(cr)
return cr
return start
@coroutine
def produce(target):
while True:
n = (yield)
target.send(n*10)
@coroutine
def sink():
try:
while True:
n = (yield)
print(n)
except GeneratorExit:
pass
sk = sink()
pipe = produce(sink())
Run Code Online (Sandbox Code Playgroud)
使用此代码,我得到:
>>> pipe.send(10)
100
Run Code Online (Sandbox Code Playgroud)
然后我想得到返回值而不是打印它,我试图从接收器中产生:
@coroutine
def sink():
try:
while True:
yield (yield)
except GeneratorExit:
pass
Run Code Online (Sandbox Code Playgroud)
但它似乎不起作用,pipe.send(10)仍然返回None而不是发电机.
那么如何获得返回值呢?
我希望能够从许多异步协同程序中获益.Asyncio as_completed有点接近我正在寻找的东西(即我希望任何协同程序能够随时返回到调用者然后继续),但这似乎只允许常规协同程序返回一次.
这是我到目前为止所拥有的:
import asyncio
async def test(id_):
print(f'{id_} sleeping')
await asyncio.sleep(id_)
return id_
async def test_gen(id_):
count = 0
while True:
print(f'{id_} sleeping')
await asyncio.sleep(id_)
yield id_
count += 1
if count > 5:
return
async def main():
runs = [test(i) for i in range(3)]
for i in asyncio.as_completed(runs):
i = await i
print(f'{i} yielded')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Run Code Online (Sandbox Code Playgroud)
替换runs = [test(i) for i in range(3)]为runs = [test_gen(i) for i …
我正在经历共同惯例的概念,以及它在kotlin中的使用和实现.
我用Google搜索并阅读了几个答案,就其在架构和性能方面与线程的不同之处而言.
这里解释得很好,
很公平,合作例程很棒,没有内存开销,性能卓越,没有死锁,竞争条件等等,而且易于使用.
现在,这里有一些事情,我很困惑,并希望更清楚 -
协同例程很好用,但它如何利用多个内核来提高性能.
在Lua 5.1中,从不让协程正常结束有多糟糕?换句话说,如果一个协程收益但是我从来没有恢复它,它是否会在程序完成之前留下很多州?
cor=coroutine.wrap(somefunc)
while true do
done=cor()
if done then -- coroutine exited with "return true"
break
else -- coroutine yielded with "coroutine.yield(false)"
if some_condition then break end
end
end
function somefunc()
-- do something
coroutine.yield(false)
-- do some more
return true
end
Run Code Online (Sandbox Code Playgroud)
根据上面伪代码中的some_condition,协程可能永远不会被恢复,因此可能永远不会正确地"结束".
我可以这样做几十个协同程序而不必担心吗?将协同程序置于此状态是否安全?这个很贵吗?
此示例已用于另一个问题,以说明协同程序如何用于编写视频游戏中的过场动画:
bob.walkto(jane)
bob.lookat(jane)
bob.say("How are you?")
wait(2)
jane.say("Fine")
...
Run Code Online (Sandbox Code Playgroud)
每个函数产生主动引擎,它在恢复协程之前进行动画,定时等.协程的可能替代方案是事件队列而不是代码,但是必须实现控制逻辑和循环作为事件.是否有其他可用于实现此类功能的协同程序的替代方案?我见过一些文章中提到的回调,但我不确定代码的外观.
我在python中有一个协程(增强型生成器),在数据结束后要执行一些代码:
def mycoroutine():
try:
while True:
data = (yield)
print data
finally:
raise ValueError
print "END"
co = mycoroutine()
co.next()
for i in (1,2,3):
co.send(i)
Run Code Online (Sandbox Code Playgroud)
该ValueError异常没有提出,但解释简单地打印:
Exception ValueError: ValueError() in <generator object mycoroutine at 0x2b59dfa23d20> ignored
Run Code Online (Sandbox Code Playgroud)
有没有办法在调用者中捕获异常?
在不久前的博客文章中,Scott Vokes描述了与lua使用C函数实现协程相关的技术问题,setjmp并且longjmp:
Lua协同程序的主要限制是,由于它们是用setjmp(3)和longjmp(3)实现的,所以你不能用它们从Lua调用C代码调用回调用回调用C的Lua,因为嵌套的longjmp将破坏C函数的堆栈帧.(这是在运行时检测到的,而不是静默失败.)
我没有发现这在实践中是一个问题,我不知道有什么方法可以修复它而不损坏Lua的可移植性,这是我最喜欢的Lua之一 - 它几乎可以运行任何ANSI C编译器和适度的空间.使用Lua意味着我可以轻装上阵.:)
我已经使用了很多协同程序,我认为我已经广泛地理解了发生了什么setjmp,longjmp做了什么和做了什么,但是我在某个时候读到了它,并意识到我并没有真正理解它.为了弄明白这一点,我尝试制作一个我认为应该根据描述引起问题的程序,相反它似乎工作正常.
然而,我看到其他一些地方人们似乎声称存在问题:
问题是:
这是我制作的代码.在我的测试中,它与lua 5.3.1链接,编译为C代码,测试本身在C++ 11标准下编译为C++代码.
extern "C" {
#include <lauxlib.h>
#include <lua.h>
}
#include <cassert>
#include <iostream>
#define CODE(C) \
case C: { \
std::cout << "When returning to " << where << " got code '" #C "'" << std::endl; \
break; \
}
void handle_resume_code(int code, const char * where) {
switch (code) {
CODE(LUA_OK) …Run Code Online (Sandbox Code Playgroud) 给定一个返回模型的API(由Retrofit实现).我将一个老式的Call包含在一个Deferred使用extention函数中:
fun <T> Call<T>.toDeferred(): Deferred<T> {
val deferred = CompletableDeferred<T>()
// cancel request as well
deferred.invokeOnCompletion {
if (deferred.isCancelled) {
cancel()
}
}
enqueue(object : Callback<T> {
override fun onFailure(call: Call<T>?, t: Throwable) {
deferred.completeExceptionally(t)
}
override fun onResponse(call: Call<T>?, response: Response<T>) {
if (response.isSuccessful) {
deferred.complete(response.body()!!)
} else {
deferred.completeExceptionally(HttpException(response))
}
}
})
return deferred
}
Run Code Online (Sandbox Code Playgroud)
现在我可以得到这样的模型:
data class Dummy(val name: String, val age: Int)
fun getDummy(): Deferred<Dummy> = api.getDummy().toDeferred()
Run Code Online (Sandbox Code Playgroud)
但是如何修改里面的对象 …