fiber.yield() 和 fiber.testcancel() 的 Tarantool 纤维行为
Tarantool fiber behavior with fiber.yield() and fiber.testcancel()
我 运行 在构建基于纤程的 Ta运行 工具应用程序时出现意外行为。
我的代码的简单复制器如下所示:
local log = require('log')
local fiber = require('fiber')
box.cfg{}
local func = function()
for i = 1, 100000 do
if pcall(fiber.testcancel) ~= true then
return 1
end
fiber.yield()
end
return 0
end
local wrapfunc = function()
local ok, resp = pcall(func)
log.info(ok)
log.info(resp)
end
for _ = 1, 100 do
local myfiber = fiber.create(wrapfunc)
fiber.sleep(0.02)
fiber.kill(myfiber)
end
并打印到日志 false, fiber is cancelled
。此外,如果我使用以下 func
:
local func = function()
for i = 1, 100000 do
if pcall(fiber.testcancel) ~= true then
return 1
end
pcall(fiber.yield)
end
return 0
end
它打印到日志 true, 1
,如果我使用
local func = function()
for i = 1, 100000 do
if pcall(fiber.testcancel) ~= true then
return 1
end
if pcall(fiber.yield) ~= true then
return 2
end
end
return 0
end
它打印到日志 true, 2
。
我预计在从 运行 myfiber
屈服后,如果控制 returns 到外部光纤并调用 fiber.kill(myfiber)
,下一次控制 returns 到取消的 myfiber
我们将处于循环迭代的末尾,并且在下一次迭代代码将成功 return 1。但是,func
的工作以抛出错误结束 fiber is cancelled
,而不是 return。那么高产纤维的真实生命周期是如何运作的呢?
实际上,这里并没有意外的行为。我相信这主要是文档问题。让我解释。我稍微简化了您的示例:
#!/usr/bin/env tarantool
local fiber = require('fiber')
local f1 = function() fiber.yield() end
local f2 = function() pcall(fiber.yield) end
local func = function(fn)
fn()
if not pcall(fiber.testcancel) then
return 'fiber.testcancel() failed'
end
end
local fiber1 = fiber.create(function() print(pcall(func, f1)) end)
fiber.kill(fiber1)
local fiber2 = fiber.create(function() print(pcall(func, f2)) end)
fiber.kill(fiber2)
输出将是:
false fiber is cancelled
true fiber.testcancel() failed
当您调用 fiber.kill
、fiber.yield()
或 fiber.sleep()
时只会引发错误,因此您的光纤无法到达 fiber.testcancel
并且会挂掉。当您执行 pcall(fiber.yield)
时,您基本上会抑制此错误并继续。然后 fiber.testcancel
检查其纤程状态并重新引发异常。但这是一个愚蠢的例子。
现在,随着代码块越来越大,当涉及到大量函数调用时,您通常希望在 yield
期间捕获这些错误,做一些完成工作并调用 fiber.testcancel()
向上提升错误(想象在大堆栈跟踪的不同部分进行多次此类检查)。我相信这是基本用例,fiber.testcancel
被引入是为了讨论它的设计是否可用。
P.s。是的,没有记录此类 yield 调用的偶尔异常。至少我在 fiber 页面
中找不到任何东西
我 运行 在构建基于纤程的 Ta运行 工具应用程序时出现意外行为。
我的代码的简单复制器如下所示:
local log = require('log')
local fiber = require('fiber')
box.cfg{}
local func = function()
for i = 1, 100000 do
if pcall(fiber.testcancel) ~= true then
return 1
end
fiber.yield()
end
return 0
end
local wrapfunc = function()
local ok, resp = pcall(func)
log.info(ok)
log.info(resp)
end
for _ = 1, 100 do
local myfiber = fiber.create(wrapfunc)
fiber.sleep(0.02)
fiber.kill(myfiber)
end
并打印到日志 false, fiber is cancelled
。此外,如果我使用以下 func
:
local func = function()
for i = 1, 100000 do
if pcall(fiber.testcancel) ~= true then
return 1
end
pcall(fiber.yield)
end
return 0
end
它打印到日志 true, 1
,如果我使用
local func = function()
for i = 1, 100000 do
if pcall(fiber.testcancel) ~= true then
return 1
end
if pcall(fiber.yield) ~= true then
return 2
end
end
return 0
end
它打印到日志 true, 2
。
我预计在从 运行 myfiber
屈服后,如果控制 returns 到外部光纤并调用 fiber.kill(myfiber)
,下一次控制 returns 到取消的 myfiber
我们将处于循环迭代的末尾,并且在下一次迭代代码将成功 return 1。但是,func
的工作以抛出错误结束 fiber is cancelled
,而不是 return。那么高产纤维的真实生命周期是如何运作的呢?
实际上,这里并没有意外的行为。我相信这主要是文档问题。让我解释。我稍微简化了您的示例:
#!/usr/bin/env tarantool
local fiber = require('fiber')
local f1 = function() fiber.yield() end
local f2 = function() pcall(fiber.yield) end
local func = function(fn)
fn()
if not pcall(fiber.testcancel) then
return 'fiber.testcancel() failed'
end
end
local fiber1 = fiber.create(function() print(pcall(func, f1)) end)
fiber.kill(fiber1)
local fiber2 = fiber.create(function() print(pcall(func, f2)) end)
fiber.kill(fiber2)
输出将是:
false fiber is cancelled
true fiber.testcancel() failed
当您调用 fiber.kill
、fiber.yield()
或 fiber.sleep()
时只会引发错误,因此您的光纤无法到达 fiber.testcancel
并且会挂掉。当您执行 pcall(fiber.yield)
时,您基本上会抑制此错误并继续。然后 fiber.testcancel
检查其纤程状态并重新引发异常。但这是一个愚蠢的例子。
现在,随着代码块越来越大,当涉及到大量函数调用时,您通常希望在 yield
期间捕获这些错误,做一些完成工作并调用 fiber.testcancel()
向上提升错误(想象在大堆栈跟踪的不同部分进行多次此类检查)。我相信这是基本用例,fiber.testcancel
被引入是为了讨论它的设计是否可用。
P.s。是的,没有记录此类 yield 调用的偶尔异常。至少我在 fiber 页面
中找不到任何东西