day9 进程 线程 threading multiprocessing 队列 主机批量管理工具

本文深入探讨了进程与线程的概念、区别及应用场景,详细解析了Python GIL、threading模块的使用,包括线程锁、信号量、定时器等功能,并介绍了多进程编程的原理与实践,最后给出了一个简单的主机批量管理工具示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、进程与线程

1、进程

  • 进程是系统资源加上一个或多个线程的集合
  • 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。
  • 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。

2、线程

  • 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

  A thread is an execution context, which is all the information a CPU needs to execute a stream of instructions.

  一个线程是一个执行上下文,是一个包含CPU之心指令刘的所有信息

  Suppose you're reading a book, and you want to take a break right now, but you want to be able to come back and resume reading from the exact point where you stopped. One way to achieve that is by jotting down the page number, line number, and word number. So your execution context for reading a book is these 3 numbers.

  假设你正在读一本书,现在你想休息下,但是你想在你回来的时候能够准确地从你停止的地方继续读,实现这一点的方法是记住这个页码、行号、字数。所以你继续读一本树的条件是这三个数字

  If you have a roommate, and she's using the same technique, she can take the book while you're not using it, and resume reading from where she stopped. Then you can take it back, and resume it from where you were.

  如果你有一个室友,他使用同样的手段,你没有读这本书的时候他就可以从他上次停止的地方继续读,接着你又可以拿回来,从你所在的地方继续

  Threads work in the same way. A CPU is giving you the illusion that it's doing multiple computations at the same time. It does that by spending a bit of time on each computation. It can do that because it has an execution context for each computation. Just like you can share a book with your friend, many tasks can share a CPU.

  线程的工作方式一样,一个CPU给你一种错觉,好像同时进行多项计算,它通过每次计算花费一点时间来实现这一点,它能做到这一点是由于它有每一个计算的上下文,就好像你能够和朋友共享一本书,许多任务可以共享一个CPU。

  On a more technical level, an execution context (therefore a thread) consists of the values of the CPU's registers.

  在更技术的层面上,执行上下文(线程)由CPU寄存器的值组成。

  Last: threads are different from processes. A thread is a context of execution, while a process is a bunch of resources associated with a computation. A process can have one or many threads.

  最后:线程与进程不同。线程是执行的上下文,而进程是与计算相关联的一堆资源。一个进程可以有一个或多个线程。

  Clarification: the resources associated with a process include memory pages (all the threads in a process have the same view of the memory), file descriptors (e.g., open sockets), and security credentials (e.g., the ID of the user who started the process).

  说明:与进程相关联的资源包括内存页(进程中的所有线程都具有相同的内存视图)、文件描述符(例如打开套接字)和安全凭据(例如,启动进程的用户的ID)。

 

3、进程与线程的区别

  不同的两个概念,如不能比较进程和线程谁更快

  Threads share the address space of the process that created it; processes have their own address space.

  线程可以共享创造它的进程的地址空间,进程与进程之间则不可以共享

  Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.

  线程可以直接存取它自己进程的内存数据,进程有自己的父进程的内存数据的副本(资源的复制)。

  Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.

  线程可以直接与进程的其他线程通信;进程必须使用进程间通信来与兄弟进程通信

  New threads are easily created; new processes require duplication of the parent process.

  新线程很容易创建;新进程需要父进程的重复

  Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.

  线程可以对同一进程的线程进行相当大的控制权;进程只能对子进程进行控制。

  Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.

  对主线程的更改(取消、优先更改等)可能会影响流程的其他线程的行为;对父进程的更改不会影响子进程。

 

二、Python GIL

GIL:无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行

C python是调用OS的接口

 

三、threading 模块

1、直接调用

import threading
import time

def run(name):
    print("%s start..." % name)
    time.sleep(1)
    print("%s done..." % name)
    
r1 = threading.Thread(target=run, args=("r1",))
r2 = threading.Thread(target=run, args=("r2",))
r1.start()
r2.start()
"""
输出:
r1 start...
r2 start...
r1 done...
r2 done...
"""

2、继承式调用

class MyTread(threading.Thread):
    def __init__(self, num):
        super(MyTread, self).__init__()
        self.num = num

    def run(self):                         # 必须要在run方法下定义要运行的函数
        print("%s start..." % self.num)     # 该方法的参数一般在实例化的时候传递进来
        time.sleep(1)
        print("%s done..." % self.num)

if __name__ == "__main__":
    t1 = MyTread(1)
    t2 = MyTread(2)
    t1.start()
    t2.start()
"""
1 start...
2 start...
2 done...
1 done...
"""

3、join 和 daemon

  有些线程会执行后台任务,比如发送keepalive数据包,或者执行周期性的垃圾收集,等等。只有当主程序运行时,这些才有用,而且一旦其他非守护进程的线程退出,就可以将它们杀死。

  如果没有守护线程,您必须跟踪它们,并告诉它们退出,然后程序才能完全退出。通过将它们设置为守护线程,您可以让它们运行并忘记它们,当您的程序退出时,任何守护线程都会自动被杀死。

  join等待线程结束,否则就挂起,可以设置超时时间,如果线程在时间内没有执行结束则继续往走。

def run(n):
    print("%s start..." % n)
    time.sleep(1)
    print("%s done..." % n)

def main():
    for i in range(5):
        print(i)
        t = threading.Thread(target=run, args=(i,))
        t.start()
        # t.join(timeout=0.5)  # join() 需要等待t结束,否则就会一直在这里挂起,timeout 是超过了时间就不等待继续往下执行
    print("main done")

m = threading.Thread(target=main)
m.setDaemon(True)  # 设置m为守护线程,本代码为主线程,主线程执行完毕时,守护线程会马上退出,守护线程启动的其他线程也会同时退出
m.start()
print("program done")

"""
输出
program done
"""

  

4、线程锁Lock(互斥锁Mutex)

  一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据count = 0,此时如果有1000个线程同时对count += 1,由于内存空间共享的原因,最后count的值可能小与1000。这是由于一个线程拿到count进行加1的的时候还没有将结果返回,另一个线程又去拿到count进行加1,导致最终返回的结果小与1000。

import threading
import time
lock = threading.Lock()  # 实例化一个锁
num = 0
thread_list = []
def add(i):
    global num   # 在每个线程中都获得这个全局变量
    print("get num %s" % num, i)
    time.sleep(1)
    lock.acquire()  # 修改num时提前获得锁
    num += 1
    lock.release()  # 修改后释放锁
    print("num:", num)
for i in range(10):
    t = threading.Thread(target=add, args=(i,))
    thread_list.append(t)
    t.start()
for t in thread_list:
    t.join()
print("finally num:", num)
"""
输出:
get num 0 0
get num 0 1
get num 0 2
get num 0 3
get num 0 4
get num 0 5
get num 0 6
get num 0 7
get num 0 8
get num 0 9
num: 1
num: 2
num: 3
num: 4
num: 5
num: 6
num: 7
num: 8
num: 9
num: 10
finally num: 10
"""

 

5、递归锁RLock

说白了就是在一个大锁中还要再包含子锁,如果使用互斥锁则需要多个Lock实例相互配合才行,Rlock则可以简化

import threading

lock1 = threading.Lock()   # 如果是互斥锁则需要多个Lock实例,否则会出现死锁
lock2 = threading.Lock()
def run1():
    print("run1 start")
    lock1.acquire()
    print("run1 running")
    lock1.release()
    print("run1 done")
def run2():
    print("run2 start")
    lock2.acquire()
    run1()
    print("run2 running")
    lock2.release()
    print("run2 done")
run2()

lock = threading.RLock()  # 如果是递归锁只需要一个
def run1():
    print("run1 start")
    lock.acquire()
    print("run1 running")
    lock.release()
    print("run1 done")
def run2():
    print("run2 start")
    lock.acquire()
    run1()
    print("run2 running")
    lock.release()
    print("run2 done")
run2()

  

6、Semaphore(信号量)

可以保证统一时间只有一定的线程在执行,不至于拖垮机器

import threading
import time

sem = threading.BoundedSemaphore(2)  # 实例化信号量
def run(name):
    sem.acquire()  # 上锁
    # print("%s run..." % name)
    time.sleep(1)
    sem.release()  # 释放锁

if __name__ == '__main__':
    for i in range(10):
        t = threading.Thread(target=run, args=(i,))
        t.start()
for i in range(6):
    print(threading.active_count())  # 输出存活的线程,每次只有两条执行中,其他的都是挂起状态
    time.sleep(1)

"""
输出
11
9
7
5
3
1
"""

  

7、Timer

  这个类表示一个动作,该动作应该在经过一定的时间之后才会运行。

  定时器开始,就像线程一样,调用start()方法。通过调用thecancel()方法,可以停止定时器(在它的动作开始之前)。在执行其操作之前,计时器将等待的时间间隔可能与用户指定的时间间隔不完全相同。

def hello():
    print("hello, world")
 
t = Timer(30.0, hello)
t.start()  # after 30 seconds, "hello, world" will be printed

  

8、Event

Event是一个简单的同步对象;Event代表一个内部标志和线程,可以等待flag的设置,或者设置或清除flag本身。

如果某进程需要等待宁一个进程执行完毕之后才能执行,此时你可以使用Event

import threading
import time
event = threading.Event()  # 实例化一个Event
def light():
    count = 0
    event.set()  # 设置flag
    while True:
        if 5 < count < 9:
            event.clear()  # 清楚flag
            if count == 6:
                print('\033[5;37;41;m  read  \033[0m')
        elif count == 9:
            print('\033[5;37;42;m  green  \033[0m')
            event.set()
            count = 0
        count += 1
        time.sleep(1)
def car():
    while True:
        if event.is_set():  # 判断是否设置了flag
            print("\033[5;32;m  car run  \033[0m")
        else:
            print("\033[5;31;m  cat stop  \033[0m")
        time.sleep(1)
if __name__ == '__main__':
    Light = threading.Thread(target=light)
    Light.start()
    Car = threading.Thread(target=car)
    Car.start()

执行结果

 

四、队列 queue

1、class queue.Queue(maxsize=0) #先入先出

Queue.qsize() 返回队列的大小 
Queue.empty() 如果队列为空,返回True,反之False 
Queue.full() 如果队列满了,返回True,反之False
Queue.full 与 maxsize 大小对应 
Queue.get([block[, timeout]])获取队列,timeout等待时间 
Queue.get_nowait() 相当Queue.get(False)  没有则不会阻塞等待
非阻塞 Queue.put(item) 写入队列,timeout等待时间 
Queue.put_nowait(item) 相当Queue.put(item, False)
Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
Queue.join() 实际上意味着等到队列为空,再执行别的操作

import queue
import time
import threading

q = queue.Queue(maxsize=3)  # 先入先出,最大三个
q.put(5)
q.put(1)
q.put(3)
# print(q.get())  # 如果队列里面没有数据了就会q.get()就会挂起,直到有新的数据进入队列
def run():
    while not q.empty():  # 判断是否为空
        print(q.get())
        time.sleep(1)
        q.task_done()  # 这里每处理一次任务就发送一个task_done信号,否则q.join()会一直阻塞
    print("run end")
t = threading.Thread(target=run)
t.start()
print("wait join ")
q.join()  # 通过task_done信号判断队列是否已经为空,否则就阻塞
print("join end ")

2、class queue.LifoQueue(maxsize=0) #last in fisrt out  后入先出

使用方法与Queue类似

3、class queue.PriorityQueue(maxsize=0) #存储数据时可设置优先级的队列

q3 = queue.PriorityQueue()
q3.put((10, 'aa'))  # item的第一个对象按ascii码排序
q3.put((-1, 'aa'))
q3.put((3, 'aa'))
print(q3.get())
print(q3.get())
print(q3.get())
"""
输出
(-1, 'aa')
(3, 'aa')
(10, 'aa')
"""

  

4、消费者与生产者模型

  在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

为什么要使用生产者和消费者模式

  在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。  

什么是生产者消费者模式

  生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Glen
import queue
import threading
import time
q = queue.Queue(10)
def producer(food):  # 上产食物,桌子上最多一次放10个food
    count = 0
    while True:
        count += 1
        q.put((count, food))  # 说明是第几个food
        print("生产了第{count}个{food}".format(count=count, food=food))
        q.join()  # 阻塞,等待顾客吃完
def consumer(name):
    while True:
        count, food = q.get()  # 得到第几个food
        print("{name}吃了第{count}个{food}".format(count=count, food=food, name=name))
        time.sleep(1)
        q.task_done()  # 给队列说我吃完了,继续上food
p1 = threading.Thread(target=producer, args=("包子",))
p2 = threading.Thread(target=producer, args=("饺子",))
c1 = threading.Thread(target=consumer, args=("alex",))
c2 = threading.Thread(target=consumer, args=("glen",))
c3 = threading.Thread(target=consumer, args=("alice",))
p1.start()
p2.start()
c1.start()
c2.start()
c3.start()
"""
输出:
生产了第1个包子
alex吃了第1个包子
生产了第1个饺子
alex吃了第1个饺子
生产了第2个饺子
glen吃了第2个饺子
生产了第2个包子
alice吃了第2个包子
生产了第3个包子
alex吃了第3个包子
生产了第3个饺子
glen吃了第3个饺子
生产了第4个饺子
alice吃了第4个饺子
"""

  

五、multiprocessing 多进程

  multiprocessing是一个模块,它使用类似于threading模块的API支持产生进程。multiprocessing提供本地和远程并发性,通过使用子进程而不是线程来有效地避开全局解释器锁。由于这个原因,多处理模块允许程序员在给定的机器上充分利用多个处理器。同时支持Unix和Windows。

1、简单示例

from multiprocessing import Process
import os


def info(title):
    print(title)
    print("model name", __name__)
    print("parent process", os.getppid())   # 打印父进程id
    print("process id", os.getpid())        # 答应当前进程id
    print("------------")


def f(name):
    info("Glen")                            # 调用info
    print("hello", name)


if __name__ == '__main__':
    info("main process")
    p = Process(target=f, args=("Alex",))   # 实例化进程
    p.start()
    p.join()
"""
输出:
main process
model name __main__
parent process 17304
process id 8752
------------
Glen
model name __mp_main__
parent process 8752
process id 6008
------------
hello Alex
"""

  

2、Queue 实现进程间通信

使用方法和threading的queue类似

from multiprocessing import Process, Queue


def f(que):
    que.put([1, 3, "hello"])


if __name__ == '__main__':
    q = Queue()
    P = Process(target=f, args=(q, ))
    P.start()
    print(q.get())
    P.join()

"""
输出:
[1, 3, 'hello']
"""

  

3、Pipe 双向管道实现进程间通信

from multiprocessing import Process, Pipe


def f(conn):
    conn.send([1, 2, "hello"])      # 子进程往子管道里面send消息
    print("f receive", conn.recv()) # 接收父进程发来的消息
    conn.close()


if __name__ == '__main__':
    parent_conn, child_conn = Pipe()        # 生成两个管道实例,实现双工
    P = Process(target=f, args=(child_conn, ))
    parent_conn.send("parent send msg")     # 往父管道里面发送消息
    P.start()
    print(parent_conn.recv())               # 接收子进程发来的消息
    P.join()
"""
输出:
f receive parent send msg
[1, 2, 'hello']
"""

  

4、Manager 实现进程间通信

from multiprocessing import Process, Manager
import os


def f(md, ml):
    md["attr"] = "age"
    md["name"] = "Glen"
    ml.append(1)
    ml.append(os.getpid())
    print(ml)


if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()          # 通过manager实例化特殊的list或dict
        l = manager.list()          # 这些特殊的实例可以实现进程间的数据交换
        p_list = []
        for i in range(10):
            P = Process(target=f, args=(d, l))
            P.start()
            p_list.append(P)        # 将所有的进程实例放入list,以便下面的循环进行join
        for res in p_list:
            res.join()
        print(d)
"""
输出:
[1, 13420]
[1, 13420, 1, 12244]
[1, 13420, 1, 12244, 1, 13072]
[1, 13420, 1, 12244, 1, 13072, 1, 12052]
[1, 13420, 1, 12244, 1, 13072, 1, 12052, 1, 10472]
[1, 13420, 1, 12244, 1, 13072, 1, 12052, 1, 10472, 1, 11912]
[1, 13420, 1, 12244, 1, 13072, 1, 12052, 1, 10472, 1, 11912, 1, 12060]
[1, 13420, 1, 12244, 1, 13072, 1, 12052, 1, 10472, 1, 11912, 1, 12060, 1, 7504]
[1, 13420, 1, 12244, 1, 13072, 1, 12052, 1, 10472, 1, 11912, 1, 12060, 1, 7504, 1, 17060]
[1, 13420, 1, 12244, 1, 13072, 1, 12052, 1, 10472, 1, 11912, 1, 12060, 1, 7504, 1, 17060, 1, 5360]
{'attr': 'age', 'name': 'Glen'}
"""

  

5、进程同步

某些时候需要lock来限制进程执行的执行顺序,比如对屏幕进行输出时需要按顺序来,否则就会出现混乱。

from multiprocessing import Process, Lock
import time


def f(n, lk):
    lk.acquire()
    time.sleep(1)  # 枷锁后成为了串行
    print(n)
    lk.release()


if __name__ == '__main__':
    lock = Lock()
    for i in range(5):
        P = Process(target=f, args=(i, lock))
        P.start()

"""
输出:
1
0
3
2
4
"""

  

6、Pool 进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:

  • apply           阻塞的,相当于串行
  • apply_async     非阻塞 常用
from multiprocessing import Pool
import time


def foo(fi):
    time.sleep(1)
    return fi+10    # 这里的返回值会成为bar的参数


def bar(args):
    print("bar", args)


if __name__ == '__main__':
    pool = Pool(5)
    for i in range(10):
        pool.apply_async(func=foo, args=(i, ), callback=bar)  # callback 将上一个函数的返回值作为参数
    print("end------")
    pool.close()  # 先close然后再join,否则会出错
    pool.join()
"""
输出: 输出5个,停顿一秒再输出5ge
end------
bar 10
bar 11
bar 12
bar 13
bar 14
bar 15
bar 16
bar 17
bar 18
bar 19
"""

  

 

六、简单主机批量管理工具

需求:

  1. 主机分组
  2. 主机信息配置文件用configparser解析
  3. 可批量执行命令、发送文件,结果实时返回,执行格式如下 
    1. batch_run  -h h1,h2,h3   -g web_clusters,db_servers    -cmd  "df -h" 
    2. batch_scp   -h h1,h2,h3   -g web_clusters,db_servers  -action put  -local test.py  -remote /tmp/ 
  4. 主机用户名密码、端口可以不同
  5. 执行远程命令使用paramiko模块
  6. 批量命令需使用multiprocessing并发
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Glen

import paramiko
import threading

semaphore = threading.BoundedSemaphore(5)


class Host(object):
    def __init__(self, name, config):
        self.host_name = name
        self.ssh_port = config.getint(name, "ssh_port")
        self.ip = config.get(name, "ip")
        self.user_name = config.get(name, "user_name")
        self.group = config.get(name, "group")
        self.password = config.get(name, "password")
        self.sftp = None

    def exec_cmd(self, cmd_str):
        """执行命令"""
        semaphore.acquire()  # 上锁 一次只能由5个线程同时执行
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy)
        ssh.connect(hostname=self.ip, port=self.ssh_port, username=self.user_name, password=self.password)
        stdin, stdout, stderr = ssh.exec_command(cmd_str)
        print("---------------{host}---------------".format(host=self.host_name))
        print(stdout.read().decode("utf8"))
        semaphore.release()  # 释放锁

    def trans_connect(self):
        trans = paramiko.Transport(sock=(self.ip, self.ssh_port))
        trans.connect(username=self.user_name, password=self.password)
        self.sftp = paramiko.SFTPClient.from_transport(trans)

    def put_file(self, local_path, remote_path):
        """上传文件"""
        semaphore.acquire()
        self.trans_connect()  # 实例化sftp连接
        res = self.sftp.put(localpath=local_path, remotepath=remote_path)  # 上传文件
        print(res)
        print("上传文件成功")
        semaphore.release()

    def get_file(self, get_file, local_path):
        """下载文件"""
        semaphore.acquire()
        self.trans_connect()  # 实例化sftp连接
        self.sftp.get(get_file, local_path)
        print("下载文件{name}成功".format(name=get_file))
        semaphore.release()
        pass

  

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Glen
import configparser
import os
# from day9.host_manager.core.Host import *
from Host import *
import sys
import threading

path_conf = os.path.join(os.path.dirname(os.getcwd()), 'conf')  # 配置文件路径
path_log = os.path.join(os.path.dirname(os.getcwd()), 'log')  # log日志路径
config = configparser.ConfigParser()  # 实例化config
config.read(os.path.join(path_conf, "hosts.config"))


def help_note():
    """usage"""
    print("""
    Usage:
    -h host1,host2  # hosts
    -g group1,group2  # host group
    -cmd "cmd_str"  # exec command
    -action put -local localFile -remote remotePath  # put file to remote host
    -action get -remote remoteFile -local localPath  # get file from remote host
    """)


def handle_cmd_str():
    """处理原始命令参数,返回list列表"""
    cmd_list = {}
    parameter = sys.argv
    try:
        for i, value in enumerate(parameter):
            if parameter[i].startswith("-"):
                if parameter[i] == "-h":
                    hosts = parameter[i+1].split(",")
                    cmd_list["hosts"] = hosts
                elif parameter[i] == "-g":
                    groups = parameter[i+1].split(",")
                    cmd_list["groups"] = groups
                elif parameter[i] == "-cmd":
                    cmd_str = parameter[i+1]
                    cmd_list["cmd_str"] = cmd_str
                    cmd_list["action"] = "cmd"
                elif parameter[i] == "-action":
                    if parameter[i+1] == "put":
                        cmd_list["action"] = "put"
                        if parameter[i+2] == "-local":
                            put_file = parameter[i+3]
                            cmd_list["put_file"] = put_file
                        else:
                            help_note()
                        if parameter[i+4] == "-remote":
                            remote_path = parameter[i+5]
                            cmd_list["remote_path"] = remote_path
                        else:
                            help_note()
                    elif parameter[i+1] == "get":
                        cmd_list["action"] = "get"
                        if parameter[i+2] == "-remote":
                            get_file = parameter[i+3]
                            cmd_list["get_file"] = get_file
                        else:
                            help_note()
                        if parameter[i+4] == "-local":
                            local_path = parameter[i+5]
                            cmd_list["local_path"] = local_path
                        else:
                            help_note()
                    else:
                        help_note()
            else:
                continue
    except IndexError as cmd_str_err:
        help_note()
        print(cmd_str_err)
        exit(2)
    return cmd_list


def group_hosts(group_name):
    """return group host list"""
    host_list = []
    for host in config.sections():
        if config.get(host, "group") == group_name:
            host_list.append(host)
    return host_list


if __name__ == '__main__':
    cmd_list = handle_cmd_str()
    print(cmd_list)
    try:
        for group in cmd_list["groups"]:  # 遍历每个group
            print("---------------------group name {group}---------------------".format(group=group))
            group_hosts_list = group_hosts(group)  # 获取到这个组里面的所有主机
            for host in group_hosts_list:  # 便利这个组里面的主机
                if host in cmd_list["hosts"]:  # 如果这个主机存在命令列表里面则需要进行操作
                    if cmd_list["action"] == "cmd":
                        host = Host(host, config)
                        t = threading.Thread(target=host.exec_cmd(cmd_list["cmd_str"]))
                    elif cmd_list["action"] == "put":
                        host = Host(host, config)
                        t = threading.Thread(target=host.put_file(cmd_list["put_file"], cmd_list["remote_path"]))
                    elif cmd_list["action"] == "get":
                        host = Host(host, config)
                        t = threading.Thread(target=host.get_file(cmd_list["get_file"], cmd_list["local_path"]))
                    else:
                        help_note()
    except KeyError as cmd_list_err:
        help_note()
        print(cmd_list_err)

  

 

转载于:https://www.cnblogs.com/starcor/p/9748756.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值