python:多线程写入数据到数据库

代码功能:

以多线程的方式一边读取容器占用cpu和内存资源,一边将获得的数据写入数据库

完整代码如下:

""" 
******************************************************************************************
*                                   多线程写入数据库-最终版                                      
*-----------------------------------------------------------------------------------------
* 注意:pymysql多线程读写数据库报错:Packet sequence number wrong 
*   解决方法:  每个execute前加上互斥锁
*               lock.acquire()
*               cursor.execute(command,data)
*               lock.release()
*
******************************************************************************************
"""
import pymysql.cursors
import threading
import time
import docker


# -------------------------- 初始化 -------------------------------
print('程序初始化...')
print('建立数据库连接...')
# 创建数据库连接
cnx = pymysql.connect(host='localhost', port=3306, user='root', password='123456', db='qt', charset='utf8mb4',connect_timeout=20)
cursor = cnx.cursor()
# 定义容器名列表
container_names = ['a','b','c','d','e','f','g']  

# 创建锁
lock = threading.Lock()
# -------------------------- docker stats读取 -------------------------------
def get_container_stats(container_name):
    client = docker.from_env() # 假设你已经初始化了 Docker 客户端
    container = client.containers.get(container_name)

    stats = container.stats(stream=False)
    cpu_usage = 100 * stats['cpu_stats']['cpu_usage']['total_usage'] / stats['cpu_stats']['system_cpu_usage']
    memory_used = 100 * stats['memory_stats']['usage'] / stats['memory_stats']['limit']

    return cpu_usage, memory_used

# -------------------------- 数据库写入 -------------------------------
def mysql_data_update(container_name, cursor, cnx):
    cpu_usage, memory_used = get_container_stats(container_name)
    # 将容器状态写入数据库
    # 执行更新数据的 SQL 语句
    lock.acquire()
    cursor.execute("UPDATE container_stats SET cpu_usage = %s, memory_used = %s WHERE container_name = %s", [cpu_usage, memory_used, container_name])
    # 提交事务
    cnx.commit()
    lock.release()
    print('容器:{} 成功写入数据库'.format(container_name))

# -------------------------- 多线程 ------------------------------------
def refresh_stats(container_names, interval=1):
    while True:
        start_time = time.time()
        
        # 创建线程列表
        threads = []
        
        # 多线程1:读取容器cpu,mem
        for container_name in container_names:
            # 创建并启动线程
            thread = threading.Thread(target=mysql_data_update, args=(container_name, cursor, cnx))
            thread.start()
            threads.append(thread)

        # 等待所有线程结束
        for thread in threads:
            thread.join()
        
        end_time = time.time()
        total_time = end_time - start_time
        
        print("总时间: {:.2f} 秒".format(total_time))
        print("---------------------------------------------------------------------------------------------\n")
        time.sleep(interval)

# 调用函数进行实时刷新
refresh_stats(container_names)

代码解释

  1. 引入所需的模块:pymysql.cursors用于数据库连接和操作,threading用于多线程操作,time用于时间相关的操作,docker用于与 Docker 进行交互。

  2. get_container_stats函数:该函数通过 Docker 客户端获取指定容器的 CPU 和内存使用情况。

  3. mysql_data_update函数:该函数用于将容器的 CPU 和内存使用情况写入数据库。它首先调用 get_container_stats函数获取容器的使用情况,然后执行 SQL 语句将数据更新到数据库中。

  4. refresh_stats函数:该函数是多线程的核心部分。它使用一个无限循环来定期刷新容器的状态。在每次循环中,它创建多个线程来处理不同的容器,并调用mysql_data_update函数将容器的使用情况写入数据库。每个线程负责一个容器的处理。线程创建后,它们被添加到线程列表中,并在循环结束时等待所有线程执行完毕。之后,程序会休眠一段时间(由interval参数指定),然后再次开始新的循环。

注意:

for container_name in container_names 是一个循环语句,它用于遍历一个名为 container_names 的列表(或可迭代对象)中的每个元素,并将每个元素赋值给变量 container_name

在这段代码中,container_names 是一个包含容器名字的列表。通过使用循环语句,程序可以逐个遍历 container_names 列表中的容器名字,并将每个容器名字赋值给变量 container_name。在循环的每次迭代中,程序可以对每个容器执行相应的操作或处理。

换句话说,这个循环用于迭代处理 container_names 列表中的容器名字,以便在后续代码中使用这些容器名字执行相应的操作。

同时,代码中使用了互斥锁(lock)来确保在执行cursor.execute语句时的线程安全性,以避免出现报错:"Packet sequence number wrong"。在执行cursor.execute之前获取锁(lock.acquire()),在执行完毕后释放锁(lock.release())。 

猜你喜欢

转载自blog.csdn.net/weixin_44810982/article/details/130793138
今日推荐