Docker内部的多处理python程序
我试图在docker容器中测试python的多处理,但即使成功创建了进程(我有8个CPU,创建了8个进程),它们也总是只需要一个物理CPU。 这是我的密码:Docker内部的多处理python程序,python,docker,python-multiprocessing,Python,Docker,Python Multiprocessing,我试图在docker容器中测试python的多处理,但即使成功创建了进程(我有8个CPU,创建了8个进程),它们也总是只需要一个物理CPU。 这是我的密码: from sklearn.externals.joblib.parallel import Parallel, delayed import multiprocessing import pandas import numpy from scipy.stats import linregress import random import l
from sklearn.externals.joblib.parallel import Parallel, delayed
import multiprocessing
import pandas
import numpy
from scipy.stats import linregress
import random
import logging
def applyParallel(dfGrouped, func):
retLst = Parallel(n_jobs=multiprocessing.cpu_count())(delayed(func)(group) for name, group in dfGrouped)
return pandas.concat(retLst)
def compute_regression(df):
result = {}
(slope,intercept,rvalue,pvalue,stderr) = linregress(df.date,df.value)
result["slope"] = [slope]
result["intercept"] = [intercept]
return pandas.DataFrame(result)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logging.info("start")
random_list = []
for i in range(1,10000):
for j in range(1,100):
random_list.append({"id":i,"date":j,"value":random.random()})
df = pandas.DataFrame(random_list)
df = applyParallel(df.groupby('id'), compute_regression)
logging.info("end")
我在启动时尝试了多个docker选项,比如--cpu或--cpuset,但它总是只使用一个物理CPU。
这是Docker、python和操作系统中的一个问题吗?
Docker版本是1.13.1
cpu\u count()
的结果:
在跑步过程中,这里有一件上衣。我们可以看到主进程和8个子进程,但我觉得百分比很奇怪。
然后,如果我改为4个进程,使用的CPU总量总是相同的:
多处理。cpu\u count()
在我的机器上提供2,而不传递--cpu
选项
转到以获取有关docker容器资源的更多信息尝试从头开始创建机器(用所需的数值替换数值): 这只是为了安全起见。 现在是重要的部分: 在运行映像之前指定核心编号。下面的命令将使用8个内核
docker run -it --cpuset-cpus="0-7" your_image_name
如果您不仅在python中成功地使用了
nproc
祝您好运,并让我们了解进展情况您可以通过执行以下命令来测试多处理器是否工作正常:
$docker run-it--rm ubuntu:20.04
root@somehash:/#apt更新和apt安装压力
root@somehash:/#强调--如果您有8个内核,那么cpu 8#8
如果您有多个核心,您可以在另一个终端中测试命令htop
或top
,您应该看到所有核心都在运行。如果您使用了htop
,您应该看到如下内容
如果你在这一步。那么一切都很好。
此外,当我运行您提供的脚本时,我看到我的处理器正在按应有的方式使用,您可以看到下图。(我还添加了进程来显示它,我在ipython
终端中运行您的脚本。我还将从sklearn.externals.joblib.parallel import parallel,delayed
更改为从joblib.parallel import parallel,delayed
,因为它不适合我)
我希望提供的信息能有所帮助。对于其他线索,您可能希望从中检查您的docker
版本-“从根本上说,容器只是一个正在运行的进程,应用了一些附加的封装功能,以便将其与主机和其他容器隔离。”
Docker在主机上运行。该主机(或虚拟机)具有一定数量的物理(或虚拟)CPU。在您的案例中,multiprocessing.cpu\u count()
显示8的原因是因为这是您的系统拥有的cpu数量。使用docker选项,如--cpu
或--cpuset cpu
不会改变机器的硬件,这就是cpu计数()
报告的内容
在我目前的系统上:
# native
$ python -c 'import multiprocessing as mp; print(mp.cpu_count())'
12
# docker
$ docker run -it --rm --cpus 1 --cpuset-cpus 0 python python -c 'import multiprocessing as mp; print(mp.cpu_count())'
12
From—“默认情况下,每个容器对主机CPU周期的访问是无限的。”
但是您可以使用--cpu
或--cpuset-cpu
等选项限制容器
--CPU
可以是一个浮点数,最多可以是可用物理CPU的数量。你可以把这个数字想象成分数中的一个分子,如果你在Mac或Windows上运行Docker,它在VM中运行。您需要将Docker作为一个整体进行配置,以便为该VM分配更多CPU。docker运行的选项
不要覆盖这一点,你不能只使用虚拟机允许使用的数量。它实际上是在Linux内部运行的:(你能做一个打印(multiprocessing.cpu\u count())
并在你的问题中添加结果吗?@hansaplast我添加了屏幕快照是来自docker内部的吗?这很有魅力!
nproc
# native
$ python -c 'import multiprocessing as mp; print(mp.cpu_count())'
12
# docker
$ docker run -it --rm --cpus 1 --cpuset-cpus 0 python python -c 'import multiprocessing as mp; print(mp.cpu_count())'
12
import logging
import multiprocessing
import sys
import psutil
from joblib.parallel import Parallel, delayed
def get_logger():
logger = logging.getLogger()
if not logger.hasHandlers():
handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter("[%(process)d/%(processName)s] %(message)s")
handler.setFormatter(formatter)
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
return logger
def fn1(n):
get_logger().debug("fn1(%d); cpu# %d", n, psutil.Process().cpu_num())
if __name__ == "__main__":
get_logger().debug("main")
Parallel(n_jobs=multiprocessing.cpu_count())(delayed(fn1)(n) for n in range(1, 101))
[21/LokyProcess-2] fn1(81); cpu# 11
[28/LokyProcess-9] fn1(82); cpu# 6
[29/LokyProcess-10] fn1(83); cpu# 2
[31/LokyProcess-12] fn1(84); cpu# 0
[22/LokyProcess-3] fn1(85); cpu# 3
[23/LokyProcess-4] fn1(86); cpu# 1
[20/LokyProcess-1] fn1(87); cpu# 7
[25/LokyProcess-6] fn1(88); cpu# 3
[27/LokyProcess-8] fn1(89); cpu# 4
[21/LokyProcess-2] fn1(90); cpu# 9
[28/LokyProcess-9] fn1(91); cpu# 10
[26/LokyProcess-7] fn1(92); cpu# 11
[22/LokyProcess-3] fn1(95); cpu# 9
[29/LokyProcess-10] fn1(93); cpu# 2
[24/LokyProcess-5] fn1(94); cpu# 10
[23/LokyProcess-4] fn1(96); cpu# 1
[20/LokyProcess-1] fn1(97); cpu# 9
[23/LokyProcess-4] fn1(98); cpu# 1
[27/LokyProcess-8] fn1(99); cpu# 4
[21/LokyProcess-2] fn1(100); cpu# 5
[11/LokyProcess-2] fn1(35); cpu# 0
[11/LokyProcess-2] fn1(36); cpu# 0
[12/LokyProcess-3] fn1(37); cpu# 1
[11/LokyProcess-2] fn1(38); cpu# 0
[15/LokyProcess-6] fn1(39); cpu# 1
[17/LokyProcess-8] fn1(40); cpu# 0
[11/LokyProcess-2] fn1(41); cpu# 0
[10/LokyProcess-1] fn1(42); cpu# 1
[11/LokyProcess-2] fn1(43); cpu# 1
[13/LokyProcess-4] fn1(44); cpu# 1
[12/LokyProcess-3] fn1(45); cpu# 0
[12/LokyProcess-3] fn1(46); cpu# 1
''' Distributed load among several Docker containers using Python multiprocessing capabilities '''
import random
import time
import subprocess
import queue
from multiprocessing import Pool, Queue, Lock
LOCK = Lock()
TEST_QUEUE = Queue()
class TestWorker(object):
''' This Class is executed by each container '''
@staticmethod
def run_test(container_id, value):
''' Operation to be executed for each container '''
cmd = ['docker exec -it {0} echo "I am container {0}!, this is message: {1}"' \
.format(container_id, value)]
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
for line in process.stdout:
print(line.decode('utf-8')[:-2])
process.wait()
@staticmethod
def container(container_id):
''' Here we get a value from the shared queue '''
while not TEST_QUEUE.empty():
LOCK.acquire()
try:
value = TEST_QUEUE.get(block=False)
time.sleep(0.5)
except queue.Empty:
print("Queue empty ):")
return
print("\nProcessing: {0}\n".format(value))
LOCK.release()
TestWorker.run_test(container_id, value)
def master():
''' Main controller to set containers and test values '''
qty = input("How many containers you want to deploy: ")
msg_val = input("How many random values you want to send among this containers: ")
print("\nGenerating test messages...\n")
for _ in range(int(msg_val)):
item = random.randint(1000, 9999)
TEST_QUEUE.put(item)
ids = []
for _ in range(int(qty)):
container_id = subprocess.run(["docker", "run", "-it", "-d", "centos:7"], \
stdout=subprocess.PIPE)
container_id = container_id.stdout.decode('utf-8')[:-1]
ids.append(container_id)
pool = Pool(int(qty))
pool.map(TestWorker.container, ids)
pool.close()
master()