我只是对数据库中的服务器列表进行了一些操作
list_servers()
|> Enum.map(fn(server) ->
go_through_and_email(server)
end)
我唯一的问题是,是否有可能分别为每个服务器启动每个go_through_email(server)
进程?现在,它完成了第一个,然后进入第二个。我们可以并行运行它们吗?因为list_servers
可能有100或100个对象。
我不想使用Task.await
或Task.async
,还有其他选择可以探索吗?
答案 0 :(得分:1)
您可以使用Task.async_stream/3
。它允许您传递一个枚举并在它们上运行一个函数,并提供一个选项,使用max_concurrency
选项限制并行运行的最大任务数。默认timeout
是5000毫秒,你可能想要指定一个更大的。{/ p>
这是一个小例子:
1..20
|> Task.async_stream(fn x ->
:timer.sleep(1000)
x
end, max_concurrency: 4, timeout: 10_000)
|> Enum.each(&IO.inspect/1)
如果你运行它,你应该看到{:ok, 1}
到{:ok, 20}
每秒打印4个批次。整个事情应该在5秒内结束,正如预期的那样,在20个项目中以4个批次进行1秒钟睡眠。
答案 1 :(得分:1)
您可以做的一件事是使用import random
import pygame as pg
from pygame.math import Vector2
class Projectile(pg.sprite.Sprite):
def __init__(self, pos, game_area):
super().__init__()
self.image = pg.Surface((5, 5))
self.image.fill(pg.Color('aquamarine2'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(2, 0).rotate(random.randrange(360))
self.pos = Vector2(pos)
self.game_area = game_area
def update(self):
self.pos += self.vel
self.rect.center = self.pos
if not self.game_area.contains(self.rect):
self.kill()
def main():
screen = pg.display.set_mode((640, 480))
game_area = pg.Rect(60, 60, 520, 360)
game_area_color = pg.Color('aquamarine2')
clock = pg.time.Clock()
all_sprites = pg.sprite.Group(Projectile(game_area.center, game_area))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
all_sprites.add(Projectile(game_area.center, game_area))
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.draw.rect(screen, game_area_color, game_area, 2)
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
,但您不想使用任务模块。
另一件事是摆脱Task.start
中的go_through_email(server)
。假设Enum.map
是数据库服务器,您应该创建一个将与数据库服务器通信的GenServers,并在server
中向每个GenServer发送一条消息。
map
然后每个GenServer都会处理并行代码。当然,您需要准备好GenServers列表。这显然比明确使用Enum.map(list_of_gen_servers, &send_message_to_go_through_email(&1))
更好。
修改强>:
如果你想send / receive
,任务模块会很棒。如果您经常访问数据库服务器并且允许完全控制通信模型应该如何,GenServers将是更好的选择。
答案 2 :(得分:1)
您也可以使用GenServer。如果将list_servers()和go_through_and_email()定义为辅助函数,您应该可以执行以下操作:
defmodule ExampleGenServer do
use GenServer
## Client API
def start_link(name) do
GenServer.start_link(__MODULE__, [], name: name)
end
def go_through(name) do
GenServer.cast(name, {:go_through, name})
end
## Server API / Callbacks
def init(initial_state) do
{:ok, initial_state}
end
def handle_cast({:go_through, name}, state) do
state = go_through_and_email(server)
{:noreply, state}
end
def handle_info({:some_info}, state) do
# stuff
{:noreply, state}
end
## Helper functions
defp list_servers() do
# stuff
end
defp go_through_and_email() do
# stuff
end
end
然后你可以在一个循环中创建新的GenServer实例:
list_servers()
|> Enum.map(fn(server) ->
ExampleGenserver.start_link(server)
end)
我在休息期间很快就做到了,所以我可能会错过/弄乱一些东西;) 如果您需要有关GenServer的其他详细信息,请参阅我的Gist。它描述了GenServer客户端/服务器API,消息传递和arg传递;) 还有一件事,请记住GenServer的拆解! ;)
答案 3 :(得分:0)
您还可以将实际任务推迟到另一位主管。我无法确定您的案例中是否需要简单函数或gen服务器,但请查看simple_one_for_one
supervisor。
这种主管非常适合这种需求(发送电子邮件,如果我正确的话)。
PS。你没有说Task
,但玩Task.async_stream
和超时是另一个合适的选择。