python进阶篇-day07-进程与线程

news2024/9/24 11:24:11

day06进程与线程

一. 进程

每个软件都可以看作是一个进程(数据隔离)

软件内的多个任务可以看作是多个线程(数据共享)

单核CPU: 宏观并行, 微观并发

真正的并行必须有多核CPU

多任务介绍

概述

多任务指的是, 多个任务"同时"执行

目的

节约资源, 充分利用CPU资源, 提高效率

表现形式

并发

针对于单核CPU来讲, 如果有多个任务同时请求执行, 但是同一瞬间CPU只能执行1个(任务), 于是就安排他们交替执行.

因为时间间隔非常短, 所以宏观上看是并行, 但是微观上还是并发的.

并行

针对多核CPU来讲, 多个任务可以同时执行

进程介绍

概述

进程: 指的是可执行程序(*.exe), 也是CPU分配资源的最小单位.

线程: 进程的执行路径, 执行单元, 也是CPU调度资源的最小单位

解释:

进程: 车

线程: 车道

多进程实现

步骤

  1. 导包(multiprocessing)

  2. 创建进程对象, 关联 该进程要执行的任务(函数)

  3. 启动进程执行任务

代码
import multiprocessing, time
​
​
# 定义代码函数
def coding():
    for i in range(1, 21):
        time.sleep(1)
        print(f'正在敲代码----  {i}')
​
        
# 定义音乐函数
def music():
    for i in range(1, 21):
        time.sleep(1)
        print(f'正在听音乐****  {i}')
​
​
if __name__ == '__main__':
    # 创建进程对象
    p1 = multiprocessing.Process(target=coding)
    p2 = multiprocessing.Process(target=music)
    # 执行进程
    p1.start()
    p2.start()

进程参数

参数

target: 用于关联 进程要执行的任务的.name: 进程名, 默认是: Process-1, Process-2,...., 可以手动修改, 一 般不改.args: 可以通过 元组 的形式传递参数, 实参的个数 及 对应的数据类型 要和 形参的个数及类型 一致.kwargs: 可以通过 字典 的形式传递参数, 实参的个数 要和 形参的个数 一致.

代码演示
import multiprocessing, time
​
​
def coding(name, num):
    for i in range(1, num):
        time.sleep(0.01)
        print(f'{name}正在敲第{i}行代码-')
​
​
def music(name, num):
    for i in range(1, num):
        time.sleep(0.01)
        print(f'{name}正在听第{i}首音乐********')
​
​
if __name__ == '__main__':
    p1 = multiprocessing.Process(target=coding, args=('小明', 21))
    p2 = multiprocessing.Process(target=music, kwargs={'num': 21, 'name': '小明'})
    p11 = multiprocessing.Process(target=coding, args=('小明', 21), name='QQ')
    p22 = multiprocessing.Process(target=music, kwargs={'num': 21, 'name': '小明'}, name='WX')
    print(f'p1:{p1.name}')
    print(f'p2:{p2.name}')
    print(f'p11:{p11.name}')
    print(f'p22:{p22.name}')
    p1.start()
    p2.start()
​

main进程

解释

main程序入口也相当于一个进程, 在程序执行时遇到自定义进程会发生资源抢占, 上述代码中在输出进程对象后, 进程才启动, 所以上述的自定义进程不会和main进程强制资源, 并且自定义进程的启动需要一定时间, 此时的main进程可能已经完成自己的任务, 执行自定义进程.

图解

代码
import multiprocessing, time
​
​
def coding(name, num):
    for i in range(1, num):
        time.sleep(0.01)
        print(f'{name}正在敲第{i}行代码-')
​
​
def music(name, num):
    for i in range(1, num):
        time.sleep(0.01)
        print(f'{name}正在听第{i}首音乐********')
​
​
if __name__ == '__main__':
    p1 = multiprocessing.Process(target=coding, args=('小明', 11))
    p2 = multiprocessing.Process(target=music, kwargs={'num': 11, 'name': '小明'})
    # p11 = multiprocessing.Process(target=coding, args=('小明', 11), name='QQ')
    # p22 = multiprocessing.Process(target=music, kwargs={'num': 11, 'name': '小明'}, name='WX')
    p1.start()
    p2.start()
    # print(f'p1:{p1.name}')
    # time.sleep(0.1)
    # print(f'p2:{p2.name}')
    # time.sleep(0.1)
    # print(f'p11:{p11.name}')
    # time.sleep(0.1)
    # print(f'p22:{p22.name}')
​
    for i in range(1, 21):
        print(f'main: -------  {i}')
        time.sleep(0.1)

注: 上述代码中, 若将main中的循环放到自定义进程前, 则自定义进程不会和main抢占资源, 因为执行完main中的循环才执行到自定义进程, 可以把main函数看作栈, 从上到下执行

代码执行结果(每次可能都不一样)

进程编号

前面创建的进程为main进程的子进程, main为前面进程的父进程,

main的父进程为pycharm

程序执行默认有main函数

在操作系统中, 每个进程都有自己唯一的ID, 且当前进程被终止时, 该ID会被回收, 即: ID是可以重复使用的.

目的

  1. 查找子进程是由那个父进程创建的, 即: 找子进程和父进程的ID.

  2. 方便我们维护进程, 例如: kill -9 pid值 可以强制杀死进程.

当前编号

方式1: os模块的 getpid()方法方式2: multiprocessing模块的current_process()方法的 pid属性

当前的父进程编号

os模块的 getppid()方法 parent process: 父进程

代码演示

# 导包
import multiprocessing, time, os
​
​
# 案例: 小明一边敲着第n行代码, 一边听着第n首音乐.
# 1. 定义函数, 表示: 敲代码.
def code(name, num):
    for i in range(1, num + 1):
        print(f'{name} 正在敲第 {i} 行代码...')
        time.sleep(0.1)
        # multiprocessing模块的current_process()函数: 获取当前进程对象
        print(f'当前进程(p1)的id: {os.getpid()}, {multiprocessing.current_process().pid}, 父进程的id为: {os.getppid()}')
​
​
# 2. 定义函数, 表示: 听音乐
def music(name, count):
    for i in range(1, count + 1):
        print(f'{name} 正在听第 {i} 首音乐.........')
        time.sleep(0.1)
        print(f'当前进程(p2)的id: {os.getpid()}, {multiprocessing.current_process().pid}, 父进程的id为: {os.getppid()}')
​
​
# 在main中测试.
if __name__ == '__main__':
    # 3. 创建进程对象.
    # Process类的参数: target: 关联的函数名, name: 当前进程的名字, args:元组的形式传参. kwargs: 字典的形式传参.
    p1 = multiprocessing.Process(name='Process_QQ', target=code, args=('乔峰', 10))
    p2 = multiprocessing.Process(name='Process_Wechat', target=music, kwargs={'count': 10, 'name': '虚竹'})
​
    # print(f"p1进程的名字: {p1.name}")
    # print(f"p2进程的名字: {p2.name}")
​
    # 4. 启动进程.
    p1.start()
    p2.start()
​
    print(f'当前进程(main)的id: {os.getpid()}, {multiprocessing.current_process().pid}, 父进程的id为: {os.getppid()}')

执行效果

进程注意事项

关于进程, 你要记忆的内容: 1. 进程之间数据是相互隔离的. 例如: 微信(进程) 和 QQ(进程)之间, 数据就是相互隔离的.

  1. 默认情况下, 主进程会等待它所有的子进程 执行结束再结束.

细节: 多进程之间, 针对于 main进程的(外部资源), 每个子进程都会拷贝一份, 进行执行.

数据隔离

代码
import multiprocessing, time
​
# 需求: 定义1个列表, 然后定义两个函数, 分别往列表中添加数据, 获取数据. 
# 之后用两个进程关联这个两个函数, 启动进程并观察结果.
# 1. 定义全局变量 my_list
my_list = []
print('我是main外资源, 看看我执行了几遍!')   # 执行三次
​
# 2. 定义函数, 实现往列表中添加数据.
def write_data():
    for i in range(1, 6):
        # 具体的添加元素的动作
        my_list.append(i)
        # 打印添加动作.
        print(f'添加 {i} 成功!')
    # 细节: 添加数据完毕后, 打印结果.
    print(f'write_data函数: {my_list}')
​
# 3. 定义函数, 实现从列表中获取数据.
def read_data():
    # 休眠 3 秒, 确保 write_data函数执行完毕.
    time.sleep(3)
    # 打印结果.
    print(f'read_data函数: {my_list}')
​
​
# 在main中测试
if __name__ == '__main__':
    # 4. 创建进程对象.
    p1 = multiprocessing.Process(target=write_data)
    p2 = multiprocessing.Process(target=read_data)
​
    # 5. 启动进程
    p1.start()
    p2.start()
​
    print('我是main内资源, 看看我执行了几遍!')   # 执行一次
执行结果

(默认)主进程等待子进程结束

演示
import multiprocessing, time
​
​
# 需求: 设置子进程执行3秒, 主进程执行1秒, 观察效果.
# 1. 定义方法, 用于关联子进程的.
def my_method():
    for i in range(10):
        print(f'工作中... {i}')
        time.sleep(0.3)  # 总休眠时间 = 0.3 * 10 = 3秒
​
​
# 2. 在main方法中测试.
if __name__ == '__main__':
    # 3. 创建子进程对象, 并启动.
    p1 = multiprocessing.Process(target=my_method)
    p1.start()  # 3秒后结束.
​
    # 4. 主进程执行1秒后结束.
    time.sleep(1)
​
    # 5. 打印主进程的结束提示.
    print('主进程 main 执行结束!')
解决
  1. 设置子进程为守护进程 p1.daemon = True 推荐

    类似于: 骑士(守护) 和 公主(非守护)

  2. 手动关闭子进程 p1.terminate() 不推荐(僵尸进程)

import multiprocessing, time
​
​
# 需求: 设置子进程执行3秒, 主进程执行1秒, 观察效果.
# 1. 定义方法, 用于关联子进程的.
def my_method():
    for i in range(10):
        print(f'工作中... {i}')
        time.sleep(0.3)  # 总休眠时间 = 0.3 * 10 = 3秒
​
​
# 2. 在main方法中测试.
if __name__ == '__main__':
    # 3. 创建子进程对象, 并启动.
    p1 = multiprocessing.Process(target=my_method)
    # 方式1: 设置子进程p1为守护进程, 
    # 非守护进程是: main进程, 所以: 当main进程关闭的时候, 它的守护进程也会关闭.
    # p1.daemon = True
    p1.start()  # 3秒后结束.
​
    # 4. 主进程执行1秒后结束.
    time.sleep(1)
​
    # 方式2: 手动关闭子进程.
    # 会导致子进程变成僵尸进程, 即: 不会立即释放资源.
    # 而是交由init进程接管(充当新的父进程), 在合适的时机释放资源.
    p1.terminate()      # 不推荐使用.
​
    # 5. 打印主进程的结束提示.
    print('主进程 main 执行结束!')

二. 线程

介绍

线程是CPU调度资源的最基本单位, 进程是CPU分配资源的基本单位.进程 = 可执行程序, 文件. 即: *.exe = 进程, 微信, QQ都是进程.线程 = 进程的执行路径, 执行单元. 微信这个进程, 可以实现: 和张三聊聊天, 和李四聊天, 查看朋友圈, 微信支付... 车在车道上跑, 有: 单行道, 双车道, 四车道, 八车道...

多线程实现

无论是进程, 还是线程, 都是实现 多任务的一种方式, 目的都是: 充分利用CPU资源, 提高效率.线程的操作步骤: 1. 导包. 2. 创建线程对象. 3. 启动线程.

代码
# 导包
import threading, time
​
# 1.定义函数, 表示: 敲代码.
def coding():
    for i in range(10):
        print(f"正在敲代码... {i}")
        time.sleep(0.1)
​
​
# 2.定义函数, 表示: 听音乐
def music():
    for i in range(10):
        print(f"正在听音乐... {i}")
        time.sleep(0.1)
​
# 在main中测试.
if __name__ == '__main__':
    # 3. 创建线程对象, 分别关联上述的两个函数.
    t1 = threading.Thread(target=coding)
    t2 = threading.Thread(target=music)
​
    # 4. 启动线程.
    t1.start()
    t2.start()

带有参数

Thread类(线程类)中的参数 和 Process类(进程类)的参数几乎一致: target: 关联目标函数的. name: 线程名(Thread-1, Thread-2...) 或者 进程名(Process-1, Process-2...). args: 以 元组的 形式传参, 个数及对应的类型都要一致. kwargs: 以 字典的 形式传参, 个数要一致.

# 导包
# from threading import Thread
import threading, time
​
​
# 1. 定义函数, 实现: 小明正在敲第n行代码.
def coding(name, num):
    for i in range(1, num + 1):
        print(f'{name} 正在敲第 {i} 行代码...')
        time.sleep(0.1)
​
​
# 2. 定义函数, 实现: 小明正在听第n首音乐
def music(name, count):
    for i in range(1, count + 1):
        print(f'{name} 正在听第 {i} 首音乐......')
        time.sleep(0.1)
​
​
# 在main中测试
if __name__ == '__main__':
    # 3. 创建线程对象.
    t1 = threading.Thread(name='杨过', target=coding, args=('乔峰', 10))
    t2 = threading.Thread(name='大雕', target=music, kwargs={'count': 10, 'name': '慕容复'})
    # print(f't1线程的名字: {t1.name}')
    # print(f't2线程的名字: {t2.name}')
​
    # 4. 启动线程.
    t1.start()
    t2.start()

线程注意事项

记忆:

  1. 多线程的执行具有 随机性(无序性), 其实就是在抢CPU的过程, 谁抢到, 谁执行.

  2. 默认情况下: 主线程会等待子线程执行结束再结束.

  3. 线程之间 会共享当前进程的 资源.

  4. 多线程环境 并发 操作共享资源, 有可能引发安全问题, 需要通过 线程同步(加锁) 的思想来解决.

关于CPU的资源分配, 调度, 思路主要有两种: 1. 均分时间片, 即: 每个进程(线程)占用CPU的时间都是 相等的. 2. 抢占式调度, 谁抢到, 谁执行. Python用的是这种.

无序

# 导包
import threading, time
​
​
# 需求: 创建多个线程, 多次运行, 观察歌词线程的执行顺序.
# 1. 定义函数, 获取线程, 并打印.
def get_info():
    # 休眠.
    time.sleep(0.5)
​
    # 获取当前的线程对象, 并打印.
    cur_thread = threading.current_thread()
    print(f'当前线程是: {cur_thread}')
​
​
​
# 在main中测试
if __name__ == '__main__':
    # 2. 创建多个线程对象.
    for i in range(10):
        th = threading.Thread(target=get_info)
        # 3. 启动线程即可.
        th.start()

(默认)主线程等待子线程结束

演示
import threading, time
​
​
# 1. 定义函数, 执行: 3秒.
def coding():
    for i in range(10):
        print(f'coding... {i}')
        time.sleep(0.3)     # 总休眠时间 = 0.3 * 10 = 3秒
​
​
# 在main中测试
if __name__ == '__main__':
    # 2. 创建线程对象.
    th = threading.Thread(target=coding)
​
    # 3. 启动线程.
    th.start()
​
    # 4. 设置主线程(main线程), 执行1秒就关闭.
    time.sleep(1)
​
    # 5. 提示即可.
    print('主线程(main)执行结束了!')
解决

设置子线程为守护线程

import threading, time
​
​
# 1. 定义函数, 执行: 3秒.
def coding():
    for i in range(10):
        print(f'coding... {i}')
        time.sleep(0.3)     # 总休眠时间 = 0.3 * 10 = 3秒
​
​
# 在main中测试
if __name__ == '__main__':
    # 2. 创建线程对象.
    # 方式1: 设置th线程为: 守护线程.
    # th = threading.Thread(target=coding, daemon=True) # 推荐使用.
​
    # 方式2: setDaemon()函数实现.
    th = threading.Thread(target=coding)
    th.setDaemon(True)  # 函数已过时, 推荐使用方式1.
​
    # 3. 启动线程.
    th.start()
​
    # 4. 设置主线程(main线程), 执行1秒就关闭.
    time.sleep(1)
​
    # 5. 提示即可.
    print('主线程(main)执行结束了!')

共享全局变量

代码
import threading
import time
​
my_list = []
print('main外输出')
​
​
def write_list():
    for i in range(10):
        my_list.append(i)
        print(f'{i} 已经添加到列表中')
    print('write_list:', my_list)
​
​
def read_list():
    time.sleep(1)
    print('read_list:', my_list)
​
​
if __name__ == '__main__':
    th1 = threading.Thread(target=write_list)
    th2 = threading.Thread(target=read_list)
    th1.start()
    th2.start()
执行结果

数据安全

多线程环境 并发 操作共享资源, 有可能引发安全问题, 需要通过 线程同步(加锁) 的思想来解决.参照4

演示:
# 导包
# 导包
import threading
import time
​
# 定义全局变量
num = 0
​
​
# 定义函数add1()累加
def add1():
    global num
    for i in range(1000000):
        num += 1
    print(f'add1: {num}')
​
​
# 定义函数add2()累加
def add2():
    global num
    for i in range(1000000):
        num += 1
    print(f'add2: {num}')
​
​
if __name__ == '__main__':
    # 创建线程对象
    th1 = threading.Thread(target=add1)
    th2 = threading.Thread(target=add2)
​
    # 启动线程
    th1.start()     # 19328862
    th2.start()     # 20000000

问题描述

两个线程分别对全局变量累加100W次, 正常应为100W 和 200W的结果,但是结果和想象不一样

原因

多线程环境 并发 操作共享资源, 引发安全问题

  • 正常情况:

  1. 假设 全局变量 global_num = 0

  2. 此时 线程t1抢到了资源, 执行累加(一次)动作, 累加后: global_num = 1

  3. 假设 线程t2抢到了资源, 执行累加(一次)动作, 累加后: global_num = 2

  • 非正常情况:

  1. 假设 全局变量 global_num = 0

  2. 此时 线程t1抢到了资源, 但是还没有来得及执行累加动作时, 被t2线程抢走了资源.

  3. 此时 线程t2读取到的 global_num = 0

  4. 此时就会出现 线程t1累加1次, global_num = 1, 线程t2累加1次, global_num = 1

  5. 综上所述, t1和t2线程一共累加了2次, 但是 global_num的值 只加了1

  6. 之所以会有这样的情况, 原因是: 1个线程在执行某1个完整动作期间, 可以被别的前程抢走资源, 就有可能引发安全问题.

解决方案

采用 线程同步 的思想, 即: 加锁

# 导包
import threading
import time
​
# 定义全局变量
num = 0
mutex = threading.Lock()
​
​
# 定义函数add1()累加
def add1():
    # 加锁
    mutex.acquire()
    global num
    for i in range(1000000):
        num += 1
    print(f'add1: {num}')
    # 释放锁
    mutex.release()
​
​
# 定义函数add2()累加
def add2():
    # 加锁
    mutex.acquire()
    global num
    for i in range(1000000):
        num += 1
    print(f'add2: {num}')
    # 释放锁
    mutex.release()
​
​
if __name__ == '__main__':
    # 创建线程对象
    th1 = threading.Thread(target=add1)
    th2 = threading.Thread(target=add2)
​
    # 启动线程
    th1.start()  # 19328862
    th2.start()  # 20000000

线程同步

用于解决多线程 并发 操作共享变量的安全问题的, 保证同一时刻只有1个线程操作共享变量.

锁的概述

互斥锁:

对共享数据进行锁定,保证同一时刻只有一个线程去操作。

注:

互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程进行等待,等锁使用完释放后,其它等待的线程再去抢这个锁。

使用步骤

  1. 创建锁

  2. 在合适的地方加锁

  3. 在合适的地方释放锁

代码
# 导包
import threading, time
​
# 1. 定义全局变量.
global_num = 0
​
# 创建锁.
mutex = threading.Lock()        # 互斥锁.
# mutex2 = threading.Lock()        # 互斥锁.
​
# 2. 定义函数1, 对全局变量 global_num累加100W次.
def get_sum1():
    # 加锁.
    mutex.acquire()
    # 声明变量为 全局变量.
    global global_num
    # 具体的累加动作.
    for i in range(1000000):
        global_num += 1
    # 解锁
    mutex.release()
    # 累加完毕后, 打印结果.
    print(f'get_sum1函数执行完毕, global_num = {global_num}')
​
​
# 3. 定义函数2, 对全局变量 global_num累加100W次.
def get_sum2():
    # 加锁.
    # mutex2.acquire()
    mutex.acquire()
    # 声明变量为 全局变量.
    global global_num
    # 具体的累加动作.
    for i in range(1000000):
        global_num += 1
    # 解锁
    # mutex2.release()
    mutex.release()
    # 累加完毕后, 打印结果.
    print(f'get_sum2函数执行完毕, global_num = {global_num}')
​
# main函数, 测试
if __name__ == '__main__':
    # 4. 创建线程对象.
    t1 = threading.Thread(target=get_sum1)
    t2 = threading.Thread(target=get_sum2)
​
    # 5. 启动线程.
    t1.start()
    t2.start()

注意事项

  1. 必须使用同一把锁, 否则可能锁不住(同一块cpu有两个锁两个门)

  2. 在合适的地方释放锁, 否则可能死锁

进程与线程的区别

关系

线程依附于进程, 没有进程就没有线程

一个进程默认提供一个线程, 可以创建多个进程

区别

  1. 进程间数据隔离

  2. 线程数据共享,但是要注意资源竞争 ,可以加互斥锁

  3. 进程比线程的资源开销大

  4. 线程是CPU调度资源的最基本单位, 进程是CPU分配资源的基本单位

  5. 线程不能独立执行, 必须存在于进程中

  6. python中 多进程单进程多线程 稳定

优缺点

  • 进程:

优点: 可以使用多核

缺点: 资源开销大

  • 线程:

优点: 资源开销小

缺点: 不可以使用多核

总结

线程依赖于进程

进程数据隔离, 线程数据共享

进程资源开销比线程资源开销大, 所以相对更稳定

无论多线程还是多进程都可以实现多任务, 目的都是: 充分利用cpu资源, 提高程序的执行效率

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2110569.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

万龙觉醒辅助:VMOS云手机辅助前期宝物选择!万龙觉醒怎么挂机?

《万龙觉醒》作为一款策略战争类游戏,玩家们在日常进行游戏时,可能会遇到游戏时间不足或无法长时间在线的问题。而通过使用VMOS云手机,可以实现24小时游戏云端在线托管,无需手动操作,彻底解放双手,随时随地…

【人工智能学习笔记】1_人工智能基础

本系列是个人学习《阿里云人工智能工程师ACA认证免费课程(2023版)》的笔记,仅为个人学习记录,欢迎交流,感谢批评指正 人工智能概述 智能的三大能力:感知、记忆与思维、学习与适应能力人工智能的定义 明斯基…

4 个最佳 3D 数据可视化工具(免费和付费)

摘要: 在当今的技术时代,数据可视化在软件测试领域发挥着相当重要的作用。简而言之,数据可视化是设计并分析数据视觉表示的过程。其中有一些顶级的数据可视化工具超出了工作范围。在数据可视化工具的帮助下,变得相当简单、更加准确。这是因为这些工具进一步消除了对手工劳动…

经济不景气?相反,这才是普通人赚钱的绝佳机会!

“日子越来越难了!”身边类似的抱怨越来越多。 想想也是,这两年市场低迷、房地产暴雷、各行业内卷.....即便兜里有钱的,也面临资产缩水的风险。 但好在从去年开始,国内外AI企业黑马连出,AI文本、图片、视频生产模型直接颠覆了传…

1990-2022年各地级市gdp、一二三产业gdp及人均gdp数据

1990-2022年各地级市gdp、一二三产业gdp及人均gdp数据 1、时间:1990-2022年 2、来源:城市统计年鉴 3、指标:年度、城市名称、城市代码、城市类别、省份标识、省份名称、国内生产总值/亿元、第一产业占GDP比重(%)、第二产业占GDP比重(%)、第…

Redis - 主从复制

文章目录 目录 文章目录 前言 1. 配置 建立复制 断开复制 传输延时 2. 主从拓扑结构 一主一从 一主多从 树状 三. 原理 数据同步 psync replicationid/replid(复制id) master_replid 和 master_replid2 offset (偏移量) psync 运行流程 全量复制 部分复制 …

算法进阶 | 必知!5大深度生成模型!

本文来源公众号“算法进阶”,仅用于学术分享,侵权删,干货满满。 原文链接:必知!5大深度生成模型! 随着Sora、diffusion、GPT等模型的大火,深度生成模型又成为了大家的焦点。 深度生成模型是一…

【简历】25届南京某一本JAVA简历:简历通过率还好,但是拿不到OFFER

注:为保证用户信息安全,姓名和学校等信息已经进行同层次变更,内容部分细节也进行了部分隐藏 简历说明 今天看一份25届南京某一本大学的Java简历。 这个简历呢,学校是一本。我们说上来先要定校招层次,这个层次就按照…

D35XT120-ASEMI新能源专用D35XT120

编辑:ll D35XT120-ASEMI新能源专用D35XT120 型号:D35XT120 品牌:ASEMI 封装:DXT-5 批号:2024 现货:50000 正向电流(Id):35A 反向耐压(VRRM&#xff0…

dubbo是什么?,能做什么?以及其工作流程

1.Dubbo是什么?能做什么? Dubbo是阿里巴巴开源的基于Java的高性能RPC分布式服务框架,现已成为Apache基金会孵化项目,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案 简单来说,dubbo…

通义灵码怎么样?分为哪些版本,看看基础能力多少分?

通义灵码,是一款基于通义大模型的智能编码辅助工具,提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码优化、注释生成、代码解释、研发智能问答、异常报错排查等能力,并针对阿里云的云服务使用场景调优,助力开发者高…

【计算机组成原理】计算机系统层次结构

计算机系统层次结构 计算机系统是一个层次结构系统,每一层都通过向上层用户提供一个抽象的简洁接口而将低层的实现细节隐藏起来。计算机解决应用问题的过程就是不同抽象层进行转换的过程 计算机系统抽象层的转换 下图描述了从最终用户希望计算机完成的应用(问题)…

Java重修笔记 第四十九天 Collections 工具类

Collections 工具类 1. public static void reverse(List<?> list) 反转集合中元素的顺序 2. public static void shuffle(List<?> list) 将集合里的元素顺序打乱 3. public static <T extends Comparable<? super T>> void sort(List<T>…

Java项目: 基于SpringBoot+mysql企业客户管理系统(含源码+数据库+答辩PPT+毕业论文)

一、项目简介 本项目是一套基于SpringBootmysql企业客户管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功…

工业相机飞拍的原理及工作原理

工业相机飞拍&#xff08;或称为工业高速相机飞行拍摄&#xff09;是一种利用高速图像捕捉技术和精密运动控制系统进行高效图像采集的先进技术。它广泛应用于工业检测、质量控制和自动化生产等领域。本文将详细探讨工业相机飞拍的原理及其工作方式。 一、工业相机飞拍的基本概…

【深度学习】卷积神经网络与 LeNet

在 softmax 回归中&#xff0c;我们使用的数据集是图像数据。这种数据的每个样本都是由一个二维像素网格组成&#xff0c;每个像素可能是一个或多个数值&#xff0c;取决于是黑白还是彩色图像。 我们之前的处理方式是通过“展平”&#xff0c;用一个标量表示一个像素&#xff…

electron 客户端 windows linux(麒麟V10)多系统离线打包 最新版 <一>

electron客户端下载、构建、打包在国内网络情况下&#xff0c;绝对不是什么易事。更不要说离线干活&#xff0c;更是难上加难。 这一篇主要讲下windows离线环境下&#xff0c;如何完成electron的下载打包。咱废话不多说&#xff0c;直接上干货。注意&#xff0c;我的大前提是完…

Nacos部分漏洞2 附POC

@[toc] Nacos部分漏洞2 附POC 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. Nacos简介 微信公…

蓝牙耳机性价比高的有哪些?年度4大高性价比热款推荐

在过去的一年里&#xff0c;市场上涌现了许多具有出色性能且价格相对亲民的蓝牙耳机&#xff0c;它们在音质、稳定性、续航能力等核心性能上表现出色&#xff0c;同时在用户最关心的价格上也展现出了极大的吸引力&#xff0c;蓝牙耳机性价比高的有哪些&#xff1f;为了帮助大家…

并发工具类(三):Semaphore

1、Semaphore介绍 Semaphore&#xff08;信号量&#xff09;也是juc包下一个线程同步工具&#xff0c;主要用于 在一个时刻允许多个线程 对共享资源进行并行操作的场景。通常情况下&#xff0c;使用 Semaphore 的过程实际上是多个线程 访问共享资源获取许可证的过程。 Semaphor…