Task.async() 可以或应该在 controller#action 中使用吗?
Can or should Task.async() be used in a controller#action?
因为Task.async()
链接到当前进程,这是否意味着如果我在控制器的动作中使用它,它会自动被杀死,或者一旦动作被执行就会死亡?
defmodule MyAppWeb.PageController do
use MyAppWeb, :controller
def index(conn, _params) do
# ????
Task.async(fn -> some_10_second_long_stuff() end)
Task.async(fn -> another_10_second_long_stuff() end)
# will they both get killed or die?
render(conn, "index.html")
end
如果可以,应该用什么代替? Task.start()
?
这 2 个 some_10_second_long_stuff
功能是“发送电子邮件”
Task.async/1
的唯一目的是创建一个可以轻松等待的任务。
除非炸毁或被杀死(阅读:如果它 returns 通常,)它只会静静地死去,并且肯定不会对调用进程做任何事情。如果任务异常终止,也会导致调用进程崩溃。
我在上面链接的文档中都有详细描述。
就是说,如果您只想产生副作用任务,请使用 Task.start/1
. If you want the task to be monitored, and restarted, if crashed, use Task.start_link/1
。如果您需要控制器进程等待任务,请使用 Task.async/1
.
When a process terminates, it will terminate with an exit reason. This
exit reason is emitted in an exit signal to all linked processes.
The default behavior when a process receives an exit signal with an
exit reason other than normal
, is to terminate and in turn emit exit
signals with the same exit reason to its linked processes. An exit
signal with reason normal
is ignored.
因此,仅仅因为一个进程结束,并不一定意味着它的链接进程也会终止。相反,一个进程必须崩溃才能导致其链接的进程崩溃。即使这样,链接进程也可以“捕获退出”以防止其崩溃。
在下面的例子中,一个进程启动了一个新的进程并链接到它,然后原来的进程结束,因为它没有更多的事情要做,即函数没有更多的语句要执行,但是链接的进程继续执行:
defmodule A do
def start do
spawn(A, :do_stuff, [])
end
def do_stuff do #This is the "do_stuff() process"...
spawn_link(A, :ticker, [10]) #...which spawns a second process, the "ticker()" process, and links to it.
IO.puts "exiting do_stuff()" #The "do_stuff()" process ends. Does the "ticker()" process also end now?
end
def ticker(0), do: IO.puts "exiting ticker()"
def ticker(num_ticks) do
:timer.sleep(1000) #sleep for 1 second
IO.write "."
ticker(num_ticks - 1)
end
end
在 iex 中:
iex(1)> A.start
exiting do_stuff
:ok
..........exiting ticker()
iex(2)>
输出显示 ticker() 进程在 do_stuff() 进程终止后继续执行 10 秒——看到十个点了吗?
将上面的输出与将 do_stuff() 更改为此时产生的输出进行比较:
def do_stuff do
spawn_link(A, :ticker, [10])
:timer.sleep(2000)
raise "I'm crashing"
IO.puts "exiting do_stuff() normally"
end
在 iex 中:
iex(1)> A.start
:ok
..iex(2)>
23:25:25.772 [error] Process #PID<0.116.0> raised an exception
** (RuntimeError) I'm crashing
a.ex:20: A.do_stuff/0
这次只有两个点
========= 回复评论:
这里是一个调用 Task.async
到 运行 ticker():
的例子
defmodule A do
def start do
spawn(A, :do_stuff, [])
:ok
end
def do_stuff do
Task.async(A, :ticker, [10])
#spawn_link(A, :ticker, [10]) #links the process executing do_stuff() and
#:timer.sleep(2000)
#raise "I'm crashing"
IO.puts "exiting do_stuff() normally"
end
def ticker(0), do: IO.puts "exiting ticker()"
def ticker(num_ticks) do
:timer.sleep(1000) #sleep for 1 second
IO.write "."
ticker(num_ticks - 1)
end
end
在 iex 中:
iex(1)> A.start
exiting do_stuff() normally
:ok
..........exiting ticker()
注意这10个点,表示在“do_stuff()进程”正常退出后执行了10秒的“ticker()进程”。
任务文档说如果您调用 Task.async()
,您 必须 调用 Task.await()
,但没有' 似乎是不调用 await() 的惩罚。我猜你会在 Task.async() 完成执行时在调用进程的邮箱中收到一条消息,如果你启动一万亿个任务,那么你可能会溢出邮箱并导致进程崩溃。
因为Task.async()
链接到当前进程,这是否意味着如果我在控制器的动作中使用它,它会自动被杀死,或者一旦动作被执行就会死亡?
defmodule MyAppWeb.PageController do
use MyAppWeb, :controller
def index(conn, _params) do
# ????
Task.async(fn -> some_10_second_long_stuff() end)
Task.async(fn -> another_10_second_long_stuff() end)
# will they both get killed or die?
render(conn, "index.html")
end
如果可以,应该用什么代替? Task.start()
?
这 2 个 some_10_second_long_stuff
功能是“发送电子邮件”
Task.async/1
的唯一目的是创建一个可以轻松等待的任务。
除非炸毁或被杀死(阅读:如果它 returns 通常,)它只会静静地死去,并且肯定不会对调用进程做任何事情。如果任务异常终止,也会导致调用进程崩溃。
我在上面链接的文档中都有详细描述。
就是说,如果您只想产生副作用任务,请使用 Task.start/1
. If you want the task to be monitored, and restarted, if crashed, use Task.start_link/1
。如果您需要控制器进程等待任务,请使用 Task.async/1
.
When a process terminates, it will terminate with an exit reason. This exit reason is emitted in an exit signal to all linked processes.
The default behavior when a process receives an exit signal with an exit reason other than
normal
, is to terminate and in turn emit exit signals with the same exit reason to its linked processes. An exit signal with reasonnormal
is ignored.
因此,仅仅因为一个进程结束,并不一定意味着它的链接进程也会终止。相反,一个进程必须崩溃才能导致其链接的进程崩溃。即使这样,链接进程也可以“捕获退出”以防止其崩溃。
在下面的例子中,一个进程启动了一个新的进程并链接到它,然后原来的进程结束,因为它没有更多的事情要做,即函数没有更多的语句要执行,但是链接的进程继续执行:
defmodule A do
def start do
spawn(A, :do_stuff, [])
end
def do_stuff do #This is the "do_stuff() process"...
spawn_link(A, :ticker, [10]) #...which spawns a second process, the "ticker()" process, and links to it.
IO.puts "exiting do_stuff()" #The "do_stuff()" process ends. Does the "ticker()" process also end now?
end
def ticker(0), do: IO.puts "exiting ticker()"
def ticker(num_ticks) do
:timer.sleep(1000) #sleep for 1 second
IO.write "."
ticker(num_ticks - 1)
end
end
在 iex 中:
iex(1)> A.start
exiting do_stuff
:ok
..........exiting ticker()
iex(2)>
输出显示 ticker() 进程在 do_stuff() 进程终止后继续执行 10 秒——看到十个点了吗?
将上面的输出与将 do_stuff() 更改为此时产生的输出进行比较:
def do_stuff do
spawn_link(A, :ticker, [10])
:timer.sleep(2000)
raise "I'm crashing"
IO.puts "exiting do_stuff() normally"
end
在 iex 中:
iex(1)> A.start
:ok
..iex(2)>
23:25:25.772 [error] Process #PID<0.116.0> raised an exception
** (RuntimeError) I'm crashing
a.ex:20: A.do_stuff/0
这次只有两个点
========= 回复评论:
这里是一个调用 Task.async
到 运行 ticker():
defmodule A do
def start do
spawn(A, :do_stuff, [])
:ok
end
def do_stuff do
Task.async(A, :ticker, [10])
#spawn_link(A, :ticker, [10]) #links the process executing do_stuff() and
#:timer.sleep(2000)
#raise "I'm crashing"
IO.puts "exiting do_stuff() normally"
end
def ticker(0), do: IO.puts "exiting ticker()"
def ticker(num_ticks) do
:timer.sleep(1000) #sleep for 1 second
IO.write "."
ticker(num_ticks - 1)
end
end
在 iex 中:
iex(1)> A.start
exiting do_stuff() normally
:ok
..........exiting ticker()
注意这10个点,表示在“do_stuff()进程”正常退出后执行了10秒的“ticker()进程”。
任务文档说如果您调用 Task.async()
,您 必须 调用 Task.await()
,但没有' 似乎是不调用 await() 的惩罚。我猜你会在 Task.async() 完成执行时在调用进程的邮箱中收到一条消息,如果你启动一万亿个任务,那么你可能会溢出邮箱并导致进程崩溃。