MPI
#include<iostream>
#include<fstream>
#include<algorithm>
#include<iomanip> //用来对输入输出操作的格式进行更加方便的控制,像C里面的格式化输出
#include<random>
#include<time.h>
#include"mpi.h"
#define N 1000 //待排序的整型数量
using namespace std;
/*从文件读取当前排序到的阶段号temp*/
int load()
{
int temp;
ifstream fp("temp.txt");
fp >> temp;
fp.close();
return temp;
}
/*该函数用来获得某个阶段,某个进程的通信伙伴*/
int Get_Partner(int my_rank, int phase) {
// 偶通信阶段,偶数为通信双方的较小进程
if (phase % 2 == 0) {
if (my_rank % 2 == 0) {
return my_rank - 1;
}
else {
return my_rank + 1;
}
}
// 奇通信阶段,奇数为通信双方的较小进程
else {
if (my_rank % 2 == 0) {
return my_rank + 1;
}
else {
return my_rank - 1;
}
}
}
/*该函数用来产生随机数,并分发至各个进程*/
void Get_Input(int A[], int local_n, int my_rank) {
int* a = NULL;
// 主进程动态开辟内存,产生随机数,分发至各个进程
if (my_rank == 0) {
ifstream data("data.txt");
a = new int[N];
for(int i=0;i<N;i++){
data >> a[i]; //从文件输入
}
data.close();
/*散射函数,将向量数据分段发送到各进程中
指向需要分发的数据的指针;分发到每一个进程的数据量;分发数据类型;
指向接收的数据的指针;接受数据量;接收数据类型;
分发数据源进程号;通信子*/
MPI_Scatter(a, local_n, MPI_INT, A, local_n, MPI_INT, 0, MPI_COMM_WORLD);
delete[] a;
}
// 其余进程接收随机数
else {
MPI_Scatter(a, local_n, MPI_INT, A, local_n, MPI_INT, 0, MPI_COMM_WORLD);
}
}
/*该函数用来合并两个进程的数据,并取较小的一半数据*/
void Merge_Low(int A[], int B[], int local_n) {
int* a = new int[local_n]; // 临时数组,存较小的数据
int p_a = 0, p_b = 0, i = 0; //分别为A,B,a三个数组的指针
//这里不同担心数组越界,因为三个数组的大小是相等的
while (i < local_n) {
if (A[p_a] < B[p_b]) {
a[i++] = A[p_a++];
}
else {
a[i++] = B[p_b++];
}
}
//存较小的一半数据
for (i = 0; i < local_n; i++) {
A[i] = a[i];
}
delete[] a;
}
/*该函数用来合并两个进程的数据,并取较大的一半数据,与前面的Merge_Low函数类似*/
void Merge_High(int A[], int B[], int local_n) {
int p_a = local_n - 1, p_b = local_n - 1, i = local_n - 1;
int* a = new int[local_n];
// 注意取最大值需要从后往前面取
while (i >= 0) {
if (A[p_a] > B[p_b]) {
a[i--] = A[p_a--];
}
else {
a[i--] = B[p_b--];
}
}
for (i = 0; i < local_n; i++) {
A[i] = a[i];
}
delete[] a;
}
/*该函数用来输出排序后的数组*/
void Print_Sorted_Vector(int A[], int local_n, int my_rank) {
int* a = NULL;
// 0号进程接收各个进程的A的分量,并输出至控制台
if (my_rank == 0) {
a = new int[N];
/*聚集函数,将各进程中的向量数据分段聚集到一个进程的大向量中*/
MPI_Gather(A, local_n, MPI_INT, a, local_n, MPI_INT, 0, MPI_COMM_WORLD);
ofstream fout("data.txt");
for (int i = 0; i < N; i++) {
if (fout) { // 如果创建成功
fout <<a[i]<< endl; // 使用与cout同样的方式进行写入
}
cout << setw(8)<<a[i]; //设置字段宽度为8位
if (i % local_n == local_n-1) {
cout << endl;
}
}
fout.close(); // 执行完操作后关闭文件句柄
cout << endl;
delete[] a;
}
// 其余进程将y分量发送至0号进程
else {
MPI_Gather(A, local_n, MPI_INT, a, local_n, MPI_INT, 0, MPI_COMM_WORLD);
}
}
int main()
{
int local_n; // 各个进程中数组的大小
int* A, * B; // A为进程中保存的数据,B为进程通信中获得的数据
int comm_sz, my_rank;//进程数,当前进程编号
int temp; //当前阶段编号
temp = load();
MPI_Init(NULL, NULL);
// 获得进程数和当前进程的编号
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
// 计算每个进程应当获得的数据量,动态开辟空间
local_n = N / comm_sz;
A = new int[local_n];
B = new int[local_n];
// 随机产生数据并分发至各个进程
Get_Input(A, local_n, my_rank);
// 先有序化本地数据
//0阶段,各进程内部进行局部排序
if(temp == 0){
sort(A, A + local_n);
}
else{
// 定理:如果p个进程运行奇偶排序算法,那么至多p个阶段后,输出列表有序
for (int i = 0; i < comm_sz; i++) {
// 获得本次交换数据的进程号
int partner = Get_Partner(my_rank, temp-1);
// 如果本次数据交换的进程号有效
if (partner != -1 && partner != comm_sz) {
// 与对方进程交换数据
/*发送缓冲区起始地址;发送数据个数;发送数据类型;目标进程的标识号;发送消息标签;
接收缓冲区初始地址;最大接收数据个数;接收数据的数据类型;源进程标识;接收消息标签;
通信器;返回的状态*/
MPI_Sendrecv(A, local_n, MPI_INT, partner, 0, B, local_n, MPI_INT, partner, 0, MPI_COMM_WORLD, MPI_STATUSES_IGNORE);
// 如果本进程号大于目标进程,就应该取值较大的部分
if (my_rank > partner) {
Merge_High(A, B, local_n);
}
// 否则应该取值较小的部分
else {
Merge_Low(A, B, local_n);
}
}
}
}
// 打印排序后的数组
Print_Sorted_Vector(A, local_n, my_rank);
MPI_Finalize();
return 0;
}
Python与docker交互
import time
import random
import docker
import paramiko # 遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接
import yaml # 用来写配置文件
import numpy as np
import os
class Sort():
def __init__(self):
# 用于配置Docker服务端的基本信息,base_url=Docker服务端的地址,version='auto'可以自动检查docker的版本
self.client = docker.APIClient(base_url='unix://var/run/docker.sock',version='auto',timeout=5) # 连接集群
self.dataFilepath = "/home/share/data.txt"
'''实现保存文件的初始化'''
def initialLocation(self,N=1000):
seed = 10
random.seed(seed) # 设置随机数生成器的种子,设置好后每次调用生成的随机数将会是同一个
a = random.sample(range(0,10000),N) # sample()方法返回一个列表
# 写出到本地
with open(self.dataFilepath, 'w') as fp:
for i in a:
fp.write("{:d}\n".format(i))
'''获取节点信息'''
def getNodeinfo(self):
node1 = self.client.nodes()[0]
node2 = self.client.nodes()[1]
info1 = {}
info2 = {}
info1['Hostname'] = node1['Description']['Hostname']
info1['State'] = node1['Status']['State']
info1['Role'] = node1['Spec']['Role']
info1['IP'] = node1['Status']['Addr']
info2['Hostname'] = node2['Description']['Hostname']
info2['State'] = node2['Status']['State']
info2['Role'] = node2['Spec']['Role']
info2['IP'] = node2['Status']['Addr']
return [info1,info2]
'''检查worker是否处于活动状态'''
def isActive(self):
nodes = self.client.nodes()
for node in nodes:
if node['Description']['Hostname']=='wy':
if node['Status']['State']=='ready':
return True
else:
return False
'''创建服务'''
def create_service(self,image = 'dispel4py/docker.openmpi',command = None,name = None):
container_spec = docker.types.ContainerSpec(image=image,command=command)
task_tmpl = docker.types.TaskTemplate(container_spec)
service_id = self.client.create_service(task_tmpl, name=name)
return service_id
'''查看服务'''
def getService(self):
services = self.client.services()
result = []
for service in services:
tmp = {}
tmp['ID'] = service['ID']
tmp['name'] = service['Spec']['Name']
tmp['Replicas'] = service['Spec']['Mode']['Replicated']['Replicas']
tmp['image'] = service['Spec']['TaskTemplate']['ContainerSpec']['Image'].split('@')[0]
result.append(tmp)
return result
'''删除服务'''
def rmService(self,name):
self.client.remove_service(name)
'''部署MPI'''
def deployMpi(self,node_num=10):
with open('/home/docker-compose.yml') as fp:
yaml_obj = yaml.load(fp.read())
yaml_obj['services']['mpi_node']['deploy']['replicas'] = node_num
main_yaml = open('/home/docker-compose.yml', 'w')
yaml.dump(yaml_obj, main_yaml)
main_yaml.close()
os.system('docker stack deploy --compose-file /home/docker-compose.yml mpi')
#time.sleep(30)
'''查看节点'''
def get_node_ls(self):
node = [] # 运行mpi程序的节点的IP
with open(file='/home/share/mpi_config_file') as fp:
for line in fp.readlines():
node.append(line.split()[0])
return node
'''运行MPI程序'''
def Run(self,currentIteration = 0):
for service in self.client.services():
if 'head' in service['Spec']['Name']:
port = service['Endpoint']['Ports'][0]['PublishedPort']
ssh = paramiko.SSHClient() # 创建一个ssh的客户端,用来连接服务器
know_host = paramiko.AutoAddPolicy() # 创建一个ssh的白名单
ssh.set_missing_host_key_policy(know_host) # 加载创建的白名单 允许连接不在know_hosts文件中的主机
# 获取运行结点的ip并保存到文件
while True:
try:
ssh.connect(hostname="localhost",port=port,username="root",password="tutorial") # 通过这个端口连接服务器mpi_head节点
if(currentIteration !=0):
print("异常处理完毕")
break
except:
print("异常处理:尝试连接主节点@"+str(port))
time.sleep(5)
chanelSSHOb = ssh.invoke_shell() # 在SSH server端创建一个交互式的shell
time.sleep(0.1)
chanelSSHOb.send('su tutorial\n') # 运行su tutorial切换用户,\n执行命令
time.sleep(0.1)
chanelSSHOb.send('cd ~\n')
time.sleep(0.1)
chanelSSHOb.send("dig tasks.mpi_node|grep ^tasks|awk '{print $5}' > mpi_config_file && sudo cp mpi_config_file ./works/\n") # 把mpi_node的IP全保存下来供openMPI使用
time.sleep(0.1)
print(chanelSSHOb.recv(9999).decode("utf8"))
nodeIP = self.get_node_ls()
lastModifiedTime = os.stat(self.dataFilepath).st_mtime
try:
chanelSSHOb.send("ssh " + nodeIP[0] + '\n')
time.sleep(0.1)
except:
pass
chanelSSHOb.send("cd ~/works\n")
time.sleep(0.1)
chanelSSHOb.send("mpicxx -std=c++11 ./sort.cpp -o ./sort -lm\n") # 编译mpi程序
time.sleep(1)
print(chanelSSHOb.recv(9999).decode("utf8"))
for i in range(currentIteration, len(nodeIP)+1): # 将当前阶段编号输出到temp文件
with open("/home/share/temp.txt", 'w') as fp:
fp.write("{:d}".format(i))
chanelSSHOb.send("mpiexec --mca btl_tcp_if_include eth0 -np "+str(len(nodeIP))+ " -hostfile ./mpi_config_file ./sort\n") # 执行mpi程序
for j in range(100):
modifiedTime = os.stat(self.dataFilepath).st_mtime
if modifiedTime!= lastModifiedTime: # 更新修改时间
lastModifiedTime = modifiedTime
break
if currentIteration==0 and (not self.isActive()): # 子节点Down,断开连接
print('\033[31m断开连接\033[0m')
return i
else:
if currentIteration==0:
time.sleep(5)
else:
time.sleep(1)
print("\033[32m保持连接\033[0m")
print(chanelSSHOb.recv(999999).decode("utf8"))
return i
if __name__ == "__main__":
sort = Sort()
sort.initialLocation()
sort.Run()
UI
import time
import tkinter as tk
from tkinter import messagebox # 弹窗
import paramiko
from PIL import Image, ImageTk # PIL图像处理
import tkinter.font as tkFont # 字体
from tkinter import FLAT, GROOVE # Button的外观效果
import numpy as np
from tkinter import ttk # tkinter的一个进阶组件,完善tkinter的一些功能
from tkinter import StringVar # 可以访问tkinter的变量的值类String
from sort import Sort
class Window():
def __init__(self):
self.OE_Swap_sort = Sort()
self.font = 'song ti'
self.createMainFrame()
def createMainFrame(self):
root = tk.Tk() # 调用Tk()方法初始化一个根窗体实例root
root.geometry("800x600") # 窗体大小
root.title("基于docker的奇偶交换排序") # 窗体标题
screenwidth = root.winfo_screenwidth() # 获取屏幕大小
screenheight = root.winfo_screenheight()
width, height = self.get_window_size(root)[:2] # 获取窗体大小
# 设置窗体的大小(width x height),与出现的位置距离窗体左上角
size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 3)
root.geometry(size) # 将窗体移动到屏幕中央
frame_main = tk.Frame(root) # 框架
frame_main.propagate(False)
frame_main.pack(expand=tk.YES, fill=tk.BOTH) # expand置1:使能fill属性;fill=BOTH:当GUI窗体大小发生变化时,小部件在X、Y两个方向跟随GUI窗体变化
frame_maintop = tk.Frame(frame_main, bg="white", height=120)
frame_maintop.pack(fill=tk.X, padx=20)
imagetop = tk.Label(frame_maintop, width=240, height=160)
imgmaintop = Image.open(r'image/docker.png')
w, h = imgmaintop.size
width = 240
height = 160
img2 = imgmaintop.resize((width, height), Image.ANTIALIAS) # 单张图像变换大小。Image.ANTIALIAS:高质量调整图像
_2img = ImageTk.PhotoImage(img2) # 显示图片
imagetop.image = _2img
imagetop.config(image=_2img)
imagetop.pack(side=tk.LEFT, padx=10, pady=10)
tk.Label(frame_maintop, text="基于docker的奇偶交换排序", bg="white", fg='black', height=4,
font=tkFont.Font(family=self.font, size=18)).pack(side=tk.LEFT)
root_canvas = tk.Canvas(root, width=800, height=420) # 画布 root:按钮的父容器
img_root = self.get_image('./image/11.png',800, 420) # 获取画布底图
root_canvas.create_image(400, 200, image=img_root)
root_canvas.pack()
img_button = self.get_image('./image/12.png', 220, 80) # 获取按钮底图
btn01 = tk.Button(root, image=img_button, compound=tk.CENTER, text="创建服务",font=(self.font,18), relief=FLAT,
command=lambda: self.create_service())
btn02 = tk.Button(root, image=img_button, compound=tk.CENTER, text="查看服务", font=(self.font, 18), relief=FLAT,
command=lambda: self.check_service())
btn03 = tk.Button(root, image=img_button, compound=tk.CENTER, text="删除服务", font=(self.font, 18), relief=FLAT,
command=lambda: self.delete_service())
btn04 = tk.Button(root, image=img_button, compound=tk.CENTER, text="查看docker集群", font=(self.font, 18),
relief=FLAT,
command=lambda: self.check_docker_swarm())
btn05 = tk.Button(root, image=img_button, compound=tk.CENTER, text="mpi集群部署", font=(self.font, 18), relief=FLAT,
command=lambda: self.mpi_deploy())
btn06 = tk.Button(root, image=img_button, compound=tk.CENTER, text="run mpi", font=(self.font, 18),
relief=FLAT,
command=lambda: self.mpi_OE_sort())
# 第四步 确定控件放置位置,并设置单击事件
btn01.place(x=100, y=200, width=220, height=80)
btn02.place(x=500, y=200, width=220, height=80)
btn03.place(x=100, y=330, width=220, height=80)
btn04.place(x=500, y=330, width=220, height=80)
btn05.place(x=100, y=460, width=220, height=80)
btn06.place(x=500, y=460, width=220, height=80)
root.mainloop() # 进入到事件(消息)循环,显示窗体
'''获取图片'''
def get_image(self, filename, width, height):
img = Image.open(filename).resize((width, height))
return ImageTk.PhotoImage(img)
'''获取窗体尺寸'''
def get_window_size(self, win, update=True):
if update:
win.update()
return win.winfo_width(), win.winfo_height(), win.winfo_x(), win.winfo_y()
'''第1个按钮绑定函数-创建服务'''
def create_service(self):
window1 = tk.Toplevel() # 创建顶级窗口1
window1.title("创建服务")
window1.geometry("400x280") # 窗体尺寸
screenwidth1 = window1.winfo_screenwidth()
screenheight1 = window1.winfo_screenheight()
width1, height1 = self.get_window_size(window1)[:2]
size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
window1.geometry(size1) # 将窗体移动到屏幕中央
# 镜像
frame1 = tk.Frame(window1, bg="white")
frame1.pack(fill=tk.X)
tk.Label(frame1, text="image: ", bg="white", fg='black', height=3,
font=tkFont.Font(family=self.font, size=15)).pack(side=tk.LEFT, padx=20, pady=10)
image_entry = tk.Entry(frame1, width=27)
image_entry.insert(0, "dispel4py/docker.openmpi")
image_entry.pack(side=tk.LEFT)
# 命令
frame2 = tk.Frame(window1, bg="white")
frame2.pack(fill=tk.X)
tk.Label(frame2, text="command: ", bg="white", fg='black', height=3,
font=tkFont.Font(family=self.font, size=15)).pack(side=tk.LEFT, padx=20, pady=10)
command_entry = tk.Entry(frame2, width=27)
command_entry.insert(0, "Default:None")
command_entry.pack(side=tk.LEFT)
# 服务
frame3 = tk.Frame(window1, bg="white")
frame3.pack(fill=tk.X)
tk.Label(frame3, text="name: ", bg="white", fg='black', height=3,
font=tkFont.Font(family=self.font, size=15)).pack(side=tk.LEFT, padx=20, pady=10)
service_entry = tk.Entry(frame3, width=27)
service_entry.insert(0, "Default:None")
service_entry.pack(side=tk.LEFT)
# 确认信息
def confirmation():
image = image_entry.get()
if command_entry.get() == "Default:None":
command = None
else:
command = command_entry.get()
if service_entry.get() == "Default:None":
service = None
else:
service = service_entry.get()
try:
ID = self.OE_Swap_sort.create_service(image, command, service)
info = "INFO:\nID:{}\nimage:{}\ncommand:{}\nname:{}".format(ID['ID'], image, command, service)
tk.messagebox.showinfo('创建成功', info, parent=window1)
except:
tk.messagebox.showerror('错误', '创建失败', parent=window1)
image_entry.delete(0, "end")
service_entry.delete(0, "end")
command_entry.delete(0, "end")
# 创建成功后“确认”
frame5 = tk.Frame(window1, bg="white")
frame5.pack(fill=tk.X)
tk.Button(frame5, text='确认', width=10, height=1, bg='white', relief=GROOVE, command=confirmation).pack(
side=tk.RIGHT, padx=10)
'''第2个按钮绑定函数-查看服务'''
def check_service(self):
window2 = tk.Toplevel() # 创建顶级窗口2
window2.title("查看服务")
window2.geometry("1000x250") # 窗体尺寸
screenwidth1 = window2.winfo_screenwidth()
screenheight1 = window2.winfo_screenheight()
width1, height1 = self.get_window_size(window2)[:2]
size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
window2.geometry(size1) # 将窗体移动到屏幕中央
tmp = self.OE_Swap_sort.getService()
service_num = len(tmp)
tree = ttk.Treeview(window2) # 创建表格对象
tree["columns"] = ("ID", "Name", "Replicas", "Image") # 定义列
tree.column("ID", width=250, anchor='center') # 设置列
tree.column("Name", width=150, anchor='center')
tree.column("Replicas", width=80, anchor='center')
tree.column("Image", width=250, anchor='center')
tree.heading("ID", text="ID", anchor='center') # 设置表头
tree.heading("Name", text="Name", anchor='center')
tree.heading("Replicas", text="Replicas", anchor='center')
tree.heading("Image", text="Image", anchor='center')
values = []
for i in range(service_num):
temp = []
for key, value in tmp[i].items():
temp.append(value)
values.append(temp)
for i in range(service_num):
tree.insert("", i, text="service" + str(i + 1), values=values[i]) # 给第0行添加数据,索引值可重复
tree.pack()
'''第3个按钮绑定函数-删除服务'''
def delete_service(self):
window3 = tk.Toplevel()
window3.title("删除服务")
window3.geometry("900x300") # 窗体尺寸
screenwidth1 = window3.winfo_screenwidth()
screenheight1 = window3.winfo_screenheight()
width1, height1 = self.get_window_size(window3)[:2]
size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
window3.geometry(size1) # 将窗体移动到屏幕中央
frame1 = tk.Frame(window3, bg="white")
frame1.pack(fill=tk.X)
tk.Label(frame1, text="name/ID:", bg="white", fg='black', height=3, width=20,
font=tkFont.Font(family=self.font, size=10)).pack(side=tk.LEFT, padx=20)
name_entry = tk.Entry(frame1, width=27)
name_entry.pack(side=tk.LEFT)
# 确认信息
def confirmation():
name_Id = name_entry.get()
try:
self.OE_Swap_sort.rmService(name_Id)
tk.messagebox.showinfo('提示', '成功删除name为{}的服务'.format(name_entry.get()), parent=window3)
except:
tk.messagebox.showerror('错误', '删除服务失败', parent=window3)
name_entry.delete(0, "end")
frame2 = tk.Frame(window3, bg="white")
frame2.pack(fill=tk.X)
tk.Button(frame2, text='确认', width=10, height=1, bg='white', relief=GROOVE, command=confirmation).pack(
anchor=tk.E, ipadx=30, ipady=0)
tmp = self.OE_Swap_sort.getService()
service_num = len(tmp)
tree = ttk.Treeview(window3) # 创建表格对象
tree["columns"] = ("ID", "Name", "Replicas", "Image") # 定义列
tree.column("ID", width=250, anchor='center') # 设置列
tree.column("Name", width=150, anchor='center')
tree.column("Replicas", width=80, anchor='center')
tree.column("Image", width=250, anchor='center')
tree.heading("ID", text="ID", anchor='center') # 设置表头
tree.heading("Name", text="Name", anchor='center')
tree.heading("Replicas", text="Replicas", anchor='center')
tree.heading("Image", text="Image", anchor='center')
values = []
for i in range(service_num):
temp = []
for key, value in tmp[i].items():
temp.append(value)
values.append(temp)
for i in range(service_num):
tree.insert("", i, text="service" + str(i + 1), values=values[i]) # 给第0行添加数据,索引值可重复
tree.pack()
'''第4个按钮绑定函数-查看docker集群'''
def check_docker_swarm(self):
window4 = tk.Toplevel()
window4.title("查看docker集群")
window4.geometry("600x200") # 窗体尺寸
screenwidth1 = window4.winfo_screenwidth()
screenheight1 = window4.winfo_screenheight()
width1, height1 = self.get_window_size(window4)[:2]
size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
window4.geometry(size1) # 将窗体移动到屏幕中央
tmp = self.OE_Swap_sort.getNodeinfo()
node_num = len(tmp)
tree = ttk.Treeview(window4) # 创建表格对象
tree["columns"] = ("Hostname", "State", "Role", "IP") # 定义列
tree.column("Hostname", width=80, anchor='center') # 设置列
tree.column("State", width=80, anchor='center')
tree.column("Role", width=80, anchor='center')
tree.column("IP", width=160, anchor='center')
tree.heading("Hostname", text="Hostname", anchor='center') # 设置表头
tree.heading("State", text="State", anchor='center')
tree.heading("Role", text="Role", anchor='center')
tree.heading("IP", text="IP", anchor='center')
values = []
for i in range(node_num):
temp = []
for key, value in tmp[i].items():
temp.append(value)
values.append(temp)
for i in range(node_num):
tree.insert("", i, text="host" + str(i + 1), values=values[i]) # #给第0行添加数据,索引值可重复
tree.pack()
'''第5个按钮绑定函数-mpi集群部署'''
def mpi_deploy(self):
window5 = tk.Toplevel()
window5.title("mpi集群部署")
window5.geometry("400x115") # 窗体尺寸
screenwidth1 = window5.winfo_screenwidth()
screenheight1 = window5.winfo_screenheight()
width1, height1 = self.get_window_size(window5)[:2]
size1 = '%dx%d+%d+%d' % (width1, height1, (screenwidth1 - width1) / 2, (screenheight1 - height1) / 3)
window5.geometry(size1) # 将窗体移动到屏幕中央
frame1 = tk.Frame(window5, bg="white")
frame1.pack(fill=tk.X)
tk.Label(frame1, text="node_num: ", bg="white", fg='black', height=3,
font=tkFont.Font(family=self.font, size=10)).pack(side=tk.LEFT, padx=20, pady=10)
num_entry = tk.Entry(frame1, width=27)
num_entry.pack(side=tk.LEFT)
# 确认信息
def confirmation():
try:
num = int(num_entry.get())
self.OE_Swap_sort.deployMpi(num)
tk.messagebox.showinfo('提示', '成功部署{}个节点的mpi集群'.format(num), parent=window5)
except:
tk.messagebox.showerror('错误', '部署集群失败', parent=window5)
num_entry.delete(0, "end")
frame2 = tk.Frame(window5, bg="white")
frame2.pack(fill=tk.X)
tk.Button(frame2, text='确认', width=10, height=1, bg='white', relief=GROOVE, command=confirmation).pack(
side=tk.RIGHT, padx=10)
'''第6个按钮绑定函数-mpi奇偶交换排序'''
def mpi_OE_sort(self):
self.OE_Swap_sort.initialLocation() # 实现保存文件的初始化
status = self.OE_Swap_sort.Run()
nodelist = self.OE_Swap_sort.get_node_ls() # 查看节点
if status != len(nodelist):
tk.messagebox.showerror('error', "异常处理中.....")
while status != len(nodelist):
self.OE_Swap_sort.deployMpi() # 重新部署mpi集群
time.sleep(10)
for service in self.OE_Swap_sort.client.services():
if 'head' in service['Spec']['Name']:
port = service['Endpoint']['Ports'][0]['PublishedPort']
ssh = paramiko.SSHClient() # 创建一个ssh的客户端,用来连接服务器
know_host = paramiko.AutoAddPolicy() # 创建一个ssh的白名单
ssh.set_missing_host_key_policy(know_host) # 加载创建的白名单
while True:
try:
ssh.connect(hostname="localhost", port=port, username="root", password="tutorial")
break
except:
print("异常处理:尝试连接主节点@" + str(port))
time.sleep(5)
tk.messagebox.showinfo('info', "异常处理完毕!")
print("continue...")
status= self.OE_Swap_sort.Run(status) # 从断开连接的阶段继续运行mpi程序
time.sleep(5)
tk.messagebox.showinfo('提示', "执行完毕")
if __name__ == '__main__':
Window = Window()