我的selenium网格上有两种浏览器类型:firefox(40个实例)和chrome(40个实例)。另外,我有一堆测试,其中一些需要在firefox上执行,其中一些在chrome下执行。他们中的一些人不在乎。
@skrrgwasme建议的第一个解决方案是将两个组上不需要特定浏览器的测试划分为最终两个队列(一个 - 在firefox上执行,第二个在chrome上执行):{ {3}}
这个解决方案很不错,但仍然可以增强:当浏览器以不同的速度处理他们的请求时,chrome将更快地完成其队列,并且firefox队列将工作更长时间。这可以通过自定义连续控制来解决,当我决定在创建池之前不使用哪个浏览器,但是当这些池已经启动时。
所以,我们应该有一个池,每个进程产生都由我们控制。
@skrrgwasme建议使用apply_async
。但我无法理解如何在python中实现这一点,因为它不像node.js那样异步。
请您分享一些例子吗?我对python有很小的经验,似乎完全坚持这个:(
答案 0 :(得分:2)
我认为最简单的方法是让每个工作进程都使用两个Queue
个对象。一个是特定于浏览器的Queue
,另一个是共享"泛型" Queue
。这样,您可以从Chrome Queue
中消耗40个进程,然后在耗尽后切换到通用Queue
,并且还有来自Firefox Queue
的40个进程消耗,然后一旦它耗尽,切换到通用Queue
。这是一个使用8个进程而不是80个进程的示例:
from multiprocessing import Pool, Manager
from Queue import Empty
import time
ff_tests = [1,2,3,4,5]
chrome_tests = [10, 11, 12, 13, 14, 15]
general_tests = [20, 21,22, 23,24,25]
def process_func(spec_queue, general_queue, browser):
while True:
try:
test = spec_queue.get_nowait()
print("Processing {} in {} process".format(test, browser))
time.sleep(2)
except Empty:
break
while True:
try:
test = general_queue.get_nowait()
print("Processing {} in {} process".format(test, browser))
time.sleep(2)
except Empty:
break
if __name__ == "__main__":
m = Manager()
ff_queue = m.Queue()
chrome_queue = m.Queue()
general_queue = m.Queue()
for queue, tests in [(ff_queue, ff_tests), (chrome_queue, chrome_tests),
(general_queue, general_tests)]:
for test in tests:
queue.put(test)
pool = Pool(8)
for _ in range(4):
pool.apply_async(process_func, args=(ff_queue, general_queue, "firefox"))
pool.apply_async(process_func, args=(chrome_queue, general_queue, "chrome"))
pool.close()
pool.join()
输出:
Processing 1 in firefox process
Processing 10 in chrome process
Processing 2 in firefox process
Processing 11 in chrome process
Processing 3 in firefox process
Processing 12 in chrome process
Processing 4 in firefox process
Processing 13 in chrome process
Processing 5 in firefox process
Processing 14 in chrome process
Processing 20 in firefox process
Processing 15 in chrome process
Processing 21 in firefox process
Processing 22 in chrome process
Processing 23 in firefox process
Processing 24 in chrome process
Processing 25 in chrome process
正如您所看到的,特定于浏览器的队列在其特定于浏览器的进程中耗尽,然后这两种类型的进程一起工作以排空通用队列。
答案 1 :(得分:1)
使用pool.apply_async
可以被认为非常类似于在上一个问题中手动设置由map
引发的每个呼叫。您只需将所有任务添加到池中,并在新工作进程可用时通过它们进行爆炸。您可以使用skrrgwasme suggested相同的每浏览器一个功能的方法。下面的代码大量借鉴了他对上一个问题的回答:
from multiprocessing import Pool
params = [1,2,3,4,5 ... ]
def ff_func(param):
# Do FireFox stuff
def ch_func(param):
# Do Chrome stuff
pool = Pool(80)
# For each parameter, add two tasks to the pool--one FF, one Chrome.
for param in params:
pool.apply_async(ff_func, param)
pool.apply_async(ch_func, param)
pool.close()
pool.join()
这里发生的是为池构建一个大的异步任务队列来处理。然后,池按照它认为合适的顺序处理所有已定义的任务。
请注意,与之前的答案不同,这并不能保证每个浏览器的最大池大小为40,因为您已要求我们更好地利用我们的资源。使用我们最多80个流程的最佳方法是尽可能让它们全部工作。
如果两种“类型”中的任何一种都不能一次使用超过40个进程,那么就无法真正改进之前的双池方法。在这种情况下,您的瓶颈只是40个进程可以完成一个或另一个队列的速度。如果您不允许使用它们,则无法使用更快队列中的自由进程; - )