假设我有以下Fabric fabfile:
import time
def part1():
print 'doing part 1'
time.sleep(1)
def part2():
print 'doing part 2'
time.sleep(10)
def bothparts():
part1()
part2()
我希望能够以自然语义运行fab -H a,b,c,d bothparts
(串行)和fab -P -H a,b,c,d bothparts
(并行)。串行执行需要44秒;并行执行需要11秒。
然而,这就是皱纹。在我的真实代码中,part1
向远程服务器发出查询,该服务器对传入的查询进行速率限制(to,let'比方说,一次两个)。因此,fab -P -H a,b,c,d bothparts
在主机a
和b
上运行完成,但在c
和d
上爆炸。
我正在寻找一种方法来限制"限速"与part1
的并发呼叫数。
我知道"bubble size",但我不能接受fab -P -z 2 -H a,b,c,d bothparts
作为答案,因为这需要22秒才能完成。我正在寻找一种方法来实现只需12秒的答案(part1
为a,b
为1秒,part1
为c,d
为1秒a,b
继续开始part2
,所有四项任务并行运行9秒,最后c,d
完成part2
时间为1秒。
我浪费了很多时间尝试使用" @ synchronized"装饰器(使用threading.Semaphore
,类似于this blog post),但是当它不起作用时,我做了一些研究,并意识到Fabric使用多个进程并行!如果我想解决问题,我需要那些多个进程互相交流。
我也不能接受手动解决方案fab -P -z 2 -H a,b,c,d part1 && fab -P -H a,b,c,d part2
;基本上我正在寻找最简单的Fabric代码,可以将其包装成一个简单的bothparts
任务。我怀疑在execute
内有bothparts
的解决方案,但我的 理想 解决方案将是{{{}内部的本地更改1}}(因为我不想因为这个实现细节而不得不重写part1
的所有调用者)。
答案 0 :(得分:0)
这是一个“技术上正确”的解决方案,不太令人满意,因为它不可组合:
import time
from fabric.decorators import parallel, runs_once
@parallel(pool_size=2)
def part1():
print 'doing part 1'
time.sleep(1)
@parallel
def part2():
print 'doing part 2'
time.sleep(10)
@runs_once
def bothparts():
execute(part1)
execute(part2)
$ fab -H a,b,c,d bothparts
这个解决方案的哲学问题是它似乎没有很好地构成;我非常不清楚如何从其他任务调用part1
或part2
,或者如何从其他任务调用bothparts
。
此外,这个bothparts
超级任务需要知道其子任务的奇怪行为。请注意,如果您移除@runs_once
上的bothparts
装饰,则最终会在每台计算机上运行part1
四次 ,然后再运行part2
四次每台机器,这是不正确的。