MoonSharp 文档五
目录
13.Coroutines(协程)
Lua中的协程
从CLR代码中的协程
从CLR代码中的协程作为CLR迭代器
注意事项
抢占式协程
14.Hardwire descriptors(硬编码描述符)
为什么需要“硬编码”
什么是“硬编码”
如何进行硬编码
硬编码的优缺点
硬编码是实现IL2CPP、AOT或iOS兼容性的必要条件吗?
术语表
15.Sandboxing(沙盒)
为什么需要沙盒化
沙盒化检查清单
移除“危险”的 API
16.Tips and tricks for Unity3D(Unity3D的提示和技巧)
支持的平台
其他建议
使用更显式的构造函数之一初始化脚本加载器
17.FAQ / Recipes
如何重定向打印函数的输出?
如何将输入重定向到Lua程序?
如何重定向Lua程序的IO流?
如何限制脚本在不丢失状态的情况下执行的指令数?
MoonSharp 文档一-CSDN博客
MoonSharp 文档二-CSDN博客
MoonSharp 文档三-CSDN博客
MoonSharp 文档四-CSDN博客
13.Coroutines(协程)
来自 C# 和 Lua。
文档地址:MoonSharp
Lua中的协程
Lua 中的协程是开箱即用的支持。实际上,只要你不故意排除协程模块(参见沙盒化),它们就可以免费使用。有很多注意事项(这些也偶然适用于原始的 Lua 实现),并在下面的 “注意事项” 部分进行了讨论。
使用任何 Lua 协程教程来操作它们。
从CLR代码中的协程
协程可以通过脚本 CreateCoroutine 方法创建,该方法接受一个必须是函数的 DynValue。
string code = @"
return function()
local x = 0
while true do
x = x + 1
coroutine.yield(x)
end
end
";
// Load the code and get the returned function
Script script = new Script();
DynValue function = script.DoString(code);
// Create the coroutine in C#
DynValue coroutine = script.CreateCoroutine(function);
// Resume the coroutine forever and ever..
while (true)
{
DynValue x = coroutine.Coroutine.Resume();
Console.WriteLine("{0}", x);
}
从CLR代码中的协程作为CLR迭代器
可以像调用迭代器一样调用协程:
string code = @"
return function()
local x = 0
while true do
x = x + 1
coroutine.yield(x)
if (x > 5) then
return 7
end
end
end
";
// Load the code and get the returned function
Script script = new Script();
DynValue function = script.DoString(code);
// Create the coroutine in C#
DynValue coroutine = script.CreateCoroutine(function);
// Loop the coroutine
string ret = "";
foreach (DynValue x in coroutine.Coroutine.AsTypedEnumerable())
{
ret = ret + x.ToString();
}
Assert.AreEqual("1234567", ret);
注意事项
现在我们来到了协程相关内容中最重要的部分。就像在原始的 Lua 中一样,无法从嵌套调用中执行 yield 操作。
特别是在 MoonSharp 中,如果你在从 Lua 调用的 C# 函数中调用一个脚本,你不能使用 yield 来恢复到 C# 调用外部的协程。
不过有一个解决办法:返回一个 TailCallRequest
类型的 DynValue
。
return DynValue.NewTailCallReq(luafunction, arg1, arg2...);
还可以指定一个 continuation(延续)——这是一段函数,它将在尾调用执行完成后被调用。
在 99% 的情况下,这可能是过度设计——甚至在大多数情况下,Lua 标准库也无法正确处理回调与 yield 的结合。但如果你计划自己实现像 `load`、`pcall` 或 `coroutine.resume` 这样的 API,这就是必需的。
另外,在某些边缘情况下,MoonSharp 处理 yield 的方式与标准 Lua 不同(在我尝试过的所有情况中,MoonSharp 的方式都更好,但谁知道呢)。例如,`tostring()` 支持在调用 `__tostring` 元方法时执行 yield 操作,而不会引发错误。
抢占式协程
在 MoonSharp 中,即使协程没有调用 `coroutine.yield`,也可以将其挂起。例如,如果想要非破坏性地限制脚本占用的 CPU 时间,这可能会很有用。但为了保持脚本的一致性,有一些需要注意的地方。
让我们从一个例子开始:
string code = @"
function fib(n)
if (n == 0 or n == 1) then
return 1;
else
return fib(n - 1) + fib(n - 2);
end
end
";
// Load the code and get the returned function
Script script = new Script(CoreModules.None);
script.DoString(code);
// get the function
DynValue function = script.Globals.Get("fib");
// Create the coroutine in C#
DynValue coroutine = script.CreateCoroutine(function);
// Set the automatic yield counter every 10 instructions.
// 10 is likely too small! Use a much bigger value in your code to avoid interrupting too often!
coroutine.Coroutine.AutoYieldCounter = 10;
int cycles = 0;
DynValue result = null;
// Cycle until we get that the coroutine has returned something useful and not an automatic yield..
for (result = coroutine.Coroutine.Resume(8);
result.Type == DataType.YieldRequest;
result = coroutine.Coroutine.Resume())
{
cycles += 1;
}
// Check the values of the operation
Assert.AreEqual(DataType.Number, result.Type);
Assert.AreEqual(34, result.Number);
步骤如下:
1. 创建一个协程
2. 将 `AutoYieldCounter` 设置为一个大于 0 的数字。1000 是一个不错的起点,可以根据需要调整。这个数字表示在执行多少条指令后,协程会主动挂起并返回给调用者。
3. 调用 `coroutine.Coroutine.Resume(...)` 并传入适当的参数。
4. 如果上述调用的返回类型是 `DataType.YieldRequest`,则不带参数调用 `coroutine.Coroutine.Resume()`。
5. 重复上一步,直到返回一个真正的结果类型。
6. 完成。
注意事项:
1. 如果代码重新进入(例如,`string.gsub` 的回调函数&#