python 进程笔记一 (概念+示例代码)

1. 进程的概念

        进程是资源分配的最小单位,也是线程的容器,线程(python 线程 (概念+示例代码))是CPU调度的基本单位,一个进程包括多个线程。

程序:例如xxx.py是一个程序

进程:一个程序运行起来后,代码+用到的资源称为进程,它是系统分配资源的基本单位。

2. 进程的状态

        在计算机工作中,其任务数往往大于CPU核数,即一定有一些任务正在执行,而另外一些任务在等待CPU执行,因此进程有了不同的状态。

        就绪态:运行的条件都已经满足,正在等待CPU执行

        执行态:CPU正在执行其功能

        等待态:等待某些条件满足,例如一个程序sleep了,此时处于等待态

3. 进程的基本使用

        multiprocessing模块时夸平台版本的多进程模块,提供了一个Process类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另外的事情。

子进程的创建

import time,multiprocessing
 
def work1():
    for i in range(5):
        print("正在运行 work1...")
        time.sleep(0.5)
 
if __name__ == '__main__':
    process_obj = multiprocessing.Process(target=work1)  # 创建子进程对象
    process_obj.start()  # 启动进程
 
    print("主进程同时在运行...")

结果:

子进程的语法结构、常用方法和常用属性:

4.进程的名称和PID

4.1 获取主进程的名称
if __name__ == '__main__':
    print(multiprocessing.current_process())

结果:

4.2 获取子进程的名称
import time,multiprocessing
 
def work1():
    print(multiprocessing.current_process())  # 获取子进程名称
    time.sleep(1)
 
if __name__ == '__main__':
    process_obj = multiprocessing.Process(target=work1)  # 创建子进程对象
    process_obj.start()  # 启动进程

结果: 

4.3 设置子进程的名称
import time,multiprocessing
 
def work1():
    print(multiprocessing.current_process())  # 获取子进程名称
    time.sleep(1)
 
if __name__ == '__main__':
    process_obj = multiprocessing.Process(target=work1, name="MyProcess")  # 创建子进程对象
    process_obj.start()  # 启动进程

结果:

4.4 获取进程PID (process id)

方式一,通过multiprocessing模块获取

获取主进程pid:

if __name__ == '__main__':
    print(multiprocessing.current_process().pid)  # 获取主进程pid

获取子进程pid:

import time,multiprocessing
 
def work1():
    print(multiprocessing.current_process().pid)  # 获取子进程pid
    time.sleep(1)
 
if __name__ == '__main__':
    process_obj = multiprocessing.Process(target=work1, name="MyProcess")  # 创建子进程对象
    process_obj.start()  # 启动进程

方式二,通过os模块获取

import os
 
 
if __name__ == '__main__':
    print(os.getpid())  # 获取主进程pid
4.5 获取子进程的父id
import time,multiprocessing,os
 
def work1():
    print("该子进程的父id是:%s" % str(os.getppid()))  # 获取子进程父id
    time.sleep(1)
 
if __name__ == '__main__':
    process_obj = multiprocessing.Process(target=work1, name="MyProcess")  # 创建子进程对象
    process_obj.start()  # 启动进程
    print(os.getpid())

结果:

4.6 杀掉进程
import time,multiprocessing,os
 
def work1():
    for i in range(10):
        print("正在运行work1...",i,"子进程pid:",multiprocessing.current_process().pid)
        time.sleep(1)
 
if __name__ == '__main__':
    process_obj = multiprocessing.Process(target=work1, name="MyProcess")  # 创建子进程对象
    process_obj.start()  # 启动进程
    print("主进程pid:", multiprocessing.current_process().pid)
 
    time.sleep(2)
    os.popen("taskkill /f /t /im " + str(multiprocessing.current_process().pid))  # 杀死主进程

结果:

也可以采用terminate()方法来中止子进程执行:

import time,multiprocessing
 
 
def work1():
    for i in range(5):
        print("正在运行work1...")
        time.sleep(0.5)
 
if __name__ == '__main__':
    process_obj1 = multiprocessing.Process(target=work1)
    process_obj1.start()
 
    time.sleep(1)
    process_obj1.terminate()  # 关闭子进程
    exit()  # 关闭主进程
 
    print("123456")

结果:

5. 进程参数、全局变量问题

5.1 进程的参数传递

方式一、使用 args 传递元组:

import time,multiprocessing
 
def work1(a, b, c):
    for i in range(5):
        print("a=%d, b=%d, c=%d" % (a,b,c))
        time.sleep(1)
 
if __name__ == '__main__':
    process_obj = multiprocessing.Process(target=work1, args=(10,20,30))  # 创建子进程对象
    process_obj.start()  # 启动进程

方式二、使用 kwargs 传递字典:

import time,multiprocessing
 
def work1(a, b, c):
    for i in range(5):
        print("a=%d, b=%d, c=%d" % (a,b,c))
        time.sleep(1)
 
if __name__ == '__main__':
    process_obj = multiprocessing.Process(target=work1, kwargs={"c":30,"a":10,"b":20})  # 创建子进程对象
    process_obj.start()  # 启动进程

方式三、混合使用 args 和 kwargs:

import time,multiprocessing
 
def work1(a, b, c):
    for i in range(5):
        print("a=%d, b=%d, c=%d" % (a,b,c))
        time.sleep(1)
 
if __name__ == '__main__':
    process_obj = multiprocessing.Process(target=work1, args=(10,),kwargs={"c":30, "b":20})  # 创建子进程对象
    process_obj.start()  # 启动进程

三种方式的结果均如下图所示

5.2  进程间不共享全局变量
import time,multiprocessing
 
g_num = 10
 
def work1():
    global g_num
    for i in range(5):
        g_num += 1
    print("---work1---",g_num)
 
def work2():
    time.sleep(2)
    print("---work2---",g_num)
 
if __name__ == '__main__':
    process_obj1 = multiprocessing.Process(target=work1)
    process_obj2 = multiprocessing.Process(target=work2)
 
    process_obj1.start()
    process_obj2.start()
 
    time.sleep(2)
    print("---mian---",g_num)

结果:

        原因是每个子进程会把主进程中的部分资源(如:变量g_num的值)分别复制到各自的子进程内,子进程内部改变的是复制的全局变量的值,不影响主进程和其它子进程的全局变量的值。

6 守护主进程

6.1没有守护主进程
import time,multiprocessing
 
 
def work1():
    for i in range(5):
        print("正在运行work1...")
        time.sleep(0.5)
 
if __name__ == '__main__':
    process_obj1 = multiprocessing.Process(target=work1)
    process_obj1.start()
 
    time.sleep(1)
    print("结束主进程")
    exit()
 
    print("123456")

结果:

可以看出主进程结束后,子进程依然在执行。

6.2 守护主进程
import time,multiprocessing
 
 
def work1():
    for i in range(5):
        print("正在运行work1...")
        time.sleep(0.5)
 
if __name__ == '__main__':
    process_obj1 = multiprocessing.Process(target=work1)
    process_obj1.daemon = True  # 设置子进程守护主进程
    process_obj1.start()
 
    time.sleep(1)
    print("结束主进程")
    exit()
 
    print("123456")

结果:

可以看到当主进程结束后,子进程也结束了。

7. 消息队列的基本操作

7.1 Queue介绍

        可以使用multprocessing模块的Queue实现多进程之间的是数据传递

        Queue本身是一个消息队列程序

7.2 创建Queue
import multiprocessing
 
# 创建队列
queue = multiprocessing.Queue(5)  # 5表示队列长度为5
7.3 向Queue中放值

方式一、使用put()方法

import multiprocessing
 
# 创建队列
queue = multiprocessing.Queue(5)  # 5表示队列长度为5
 
# 向队列放值
queue.put(1)
queue.put("hello")
queue.put([1,2,3])
queue.put((4,5,6))
queue.put({"a":10,"b":20})
# queue.put(2)  # 由于队列长度为5,当准备向队列放入第6个值时,队列就会处于阻塞状态,默认等待直到队列取出值后有空余位置

方式二、使用put_nowait()方法

import multiprocessing
 
# 创建队列
queue = multiprocessing.Queue(5)  # 5表示队列长度为5
 
# 向队列放值
queue.put_nowait(1)
queue.put_nowait("hello")
queue.put_nowait([1,2,3])
queue.put_nowait((4,5,6))
queue.put_nowait({"a":10,"b":20})
# queue.put_nowait(2)  # 超出队列长度直接报错
7.4 从Queue中取值

方式一 、使用get()方法

import multiprocessing
 
# 创建队列
queue = multiprocessing.Queue(5)  # 5表示队列长度为5
 
# 向队列放值
queue.put_nowait(1)
queue.put_nowait("hello")
queue.put_nowait([1,2,3])
queue.put_nowait((4,5,6))
queue.put_nowait({"a":10,"b":20})
 
# 取值
for i in range(6):
    value = queue.get()
    print(i,value)

当取第6个值时,由于队列已经空了,此时队列会处于阻塞状态,直到有新的值进入队列

方式二、使用get_nowait()方法

import multiprocessing
 
# 创建队列
queue = multiprocessing.Queue(5)  # 5表示队列长度为5
 
# 向队列放值
queue.put_nowait(1)
queue.put_nowait("hello")
queue.put_nowait([1,2,3])
queue.put_nowait((4,5,6))
queue.put_nowait({"a":10,"b":20})
 
# 取值
for i in range(6):
    value = queue.get_nowait()
    print(i,value)

当队列已经空后,再取值会报错

7.4 从Queue中取值

方式一 、使用get()方法

import multiprocessing

# 创建队列
queue = multiprocessing.Queue(5)  # 5表示队列长度为5

# 向队列放值
queue.put_nowait(1)
queue.put_nowait("hello")
queue.put_nowait([1, 2, 3])
queue.put_nowait((4, 5, 6))
queue.put_nowait({"a": 10, "b": 20})

# 取值
for i in range(6):
    value = queue.get()
    print(i, value)
    
# 结果
# 0 1
# 1 hello
# 2 [1, 2, 3]
# 3 (4, 5, 6)
# 4 {'a': 10, 'b': 20}

 当取第6个值时,由于队列已经空了,此时队列会处于阻塞状态,直到有新的值进入队列

方式二、使用get_nowait()方法

import multiprocessing
 
# 创建队列
queue = multiprocessing.Queue(5)  # 5表示队列长度为5
 
# 向队列放值
queue.put_nowait(1)
queue.put_nowait("hello")
queue.put_nowait([1,2,3])
queue.put_nowait((4,5,6))
queue.put_nowait({"a":10,"b":20})
 
# 取值
for i in range(6):
    value = queue.get_nowait()
    print(i,value)

当队列已经空后,再取值会报错

8. 消息队列的常见判断

8.1 判断队列是否已满
import multiprocessing
 
# 创建队列
queue = multiprocessing.Queue(3)  # 5表示队列长度为5
 
# 向队列放值
queue.put_nowait(1)
queue.put_nowait("hello")
queue.put_nowait([1,2,3])
 
# 判断队列是否已满
print(queue.full())

结果:

8.2 判断队列的消息数量
print(queue.qsize())
8.3 判断队列是否为空
print(queue.empty())

有一定的概率会打印相反的结果,因此在调用empty()方法前,通常可以sleep 0.00001秒

或使用

if queue.qsize() == 0:

来判断队列是都为空

9. Queue实现进程间数据共享

        在父进程中创建两个子进程,一个往Queue里写数据,一个从Queue里读数据,看看子进程read_queue能否读取到子进程write_queue写入到队列中的数据。

import multiprocessing,time
 
def write_queue(queue):
    """写入数据到队列"""
    for i in range(10):
        if queue.full():
            print("队列已满")
            break
        else:
            queue.put(i)
            print("已经写入:%d" % i)
            time.sleep(0.5)
 
def read_queue(queue):
    """读取队列数据并显示"""
    while True:
        if queue.qsize() == 0:
            print("队列已空")
            break
        else:
            value = queue.get()
            print("获取数据:%d" % value)
 
 
if __name__ == '__main__':
    # 创建空队列
    queue = multiprocessing.Queue(5)
 
    # 创建两个子进程
    write_q = multiprocessing.Process(target=write_queue, args=(queue,))
    read_q = multiprocessing.Process(target=read_queue, args=(queue,))
 
    write_q.start()
 
    # 让写入队列的子进程先执行
    write_q.join()
 
    read_q.start()

结果:

10. 进程池

10.1 进程池概述

        当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态生成多个进程,但如果是成百上千个进程,用手动方式创建就十分麻烦,此时就可以用到multiprocessing模块提供的Pool方法。

        初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求,但如果池中的进程数已经达到最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务。

10.2 multiprocessing.Pool常用函数

1.apply()

进程池中进程以同步方式执行任务

import multiprocessing,time
 
def copy_work(a,b):
    """用于模拟文件拷贝的函数"""
    print("正在拷贝文件...",multiprocessing.current_process(),a,b)
    time.sleep(0.5)
 
if __name__ == '__main__':
    # 创建进程池
    pool = multiprocessing.Pool(3)  # 最大允许创建3个进程
    for i in range(10):
        # 让进程池以同步方式执行copy_work
        pool.apply(copy_work,(10,20))

结果:

2.apply_async()

进程池中进程以异步方式执行任务

如果使用apply_async方式,需要做以下两点:

  (1)pool.close() 表示不再接收新的任务

  (2)pool.join() 让主进程等待进程池执行结束后再退出

import multiprocessing,time
 
def copy_work(a,b):
    """用于模拟文件拷贝的函数"""
    print("正在拷贝文件...",multiprocessing.current_process(),a,b)
    time.sleep(0.5)
 
if __name__ == '__main__':
    # 创建进程池
    pool = multiprocessing.Pool(3)  # 最大允许创建3个进程
    for i in range(10):
        # 让进程池以异步方式执行copy_work
        pool.apply_async(copy_work,(10,20))
    pool.close()
    pool.join()

结果:

10.3 进程池中的Queue

专门用于进程池中的进程间的数据共享

(1)同步方式

import multiprocessing,time
 
def write_queue(queue):
    """写入数据到队列"""
    for i in range(10):
        if queue.full():
            print("队列已满")
            break
        else:
            queue.put(i)
            print("已经写入:%d" % i)
            time.sleep(0.5)
 
def read_queue(queue):
    """读取队列数据并显示"""
    while True:
        if queue.qsize() == 0:
            print("队列已空")
            break
        else:
            value = queue.get()
            print("获取数据:%d" % value)
 
 
if __name__ == '__main__':
    # 创建进程池
    pool = multiprocessing.Pool(2)
 
    # 创建进程池中的队列
    queue = multiprocessing.Manager().Queue(5)
 
    # 使用进程池执行任务(同步方式)
    pool.apply(write_queue, (queue,))
    pool.apply(read_queue, (queue,))

结果:

(2)异步方式 

import multiprocessing,time
 
def write_queue(queue):
    """写入数据到队列"""
    for i in range(10):
        if queue.full():
            print("队列已满")
            break
        else:
            queue.put(i)
            print("已经写入:%d" % i)
            time.sleep(0.5)
 
def read_queue(queue):
    """读取队列数据并显示"""
    while True:
        if queue.qsize() == 0:
            print("队列已空")
            break
        else:
            value = queue.get()
            print("获取数据:%d" % value)
 
 
if __name__ == '__main__':
    # 创建进程池
    pool = multiprocessing.Pool(2)
 
    # 创建进程池中的队列
    queue = multiprocessing.Manager().Queue(5)
 
    # 使用进程池执行任务(异步方式)
    pool.apply_async(write_queue, (queue,))
    pool.apply_async(read_queue, (queue,))
 
    pool.close()  # 表示不再接收新的任务
    pool.join()  # 主进程会等待进程池执行结束后再退出

结果:

11. 案例:进程池实现文件夹拷贝器

目标:使用进程池实现文件夹整体拷贝到另外一个目录

思路:

import multiprocessing,time,os
 
def copy_file(source_dir, target_dir, file):
    print(multiprocessing.current_process())
    source_path = source_dir + "/" + file
    target_path = target_dir + "/" + file
    # print("%s  -->  %s" % (source_path, target_path))
 
    # 读取源文件内容
    with open(source_path,"rb") as source_file:
 
        # 创建目标文件
        with open(target_path, "wb") as target_file:
            while True:
                # 读源文件保存到目标文件
                source_file_data = source_file.read(1024)  # 每次读1024个字节
                if source_file_data:  # 判断是否完成读取源文件
                    target_file.write(source_file_data)
                else:
                    break
 
 
if __name__ == '__main__':
    source_dir = "C:/Users/DOUH/Desktop/pythonCode"  # 源文件路径
    target_dir = "C:/Users/DOUH/Desktop/test"  # 目标文件路径
 
    # 在指定位置创建test文件夹
    try:
        os.mkdir(target_dir)
    except:
        pass
 
    # 获取源文件夹中的所有的文件
    file_list = os.listdir(source_dir)
 
    # 创建进程池
    pool = multiprocessing.Pool(3)
 
 
    for file in file_list:
        # 拷贝文件
        pool.apply_async(copy_file, (source_dir, target_dir, file))
 
    pool.close()
    pool.join()

结果:

12. 案例:使用多进程向同一文件写入数据

import multiprocessing
 
# 设置回调函数
def setcallback(x):
    with open('result.txt', 'a+') as f:
        line = str(x) + "\n"
        f.write(line)
 
def multiplication(num):
    return num
 
if __name__ == '__main__':
    pool = multiprocessing.Pool(6)
    for i in range(1000):
        pool.apply_async(func=multiplication, args=(i,), callback=setcallback)
    pool.close()
    pool.join()

参考:

python 进程 (概念+示例代码)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++初阶 | [八] (下) vector 模拟实现

摘要:vector 模拟实现讲解(附代码示例),隐藏的浅拷贝,迭代器失效 在进行 vector 的模拟实现之前,我们先粗略浏览一下 stl_vector.h 文件中的源码来确定模拟实现的大体框架。 这里提供一些粗略浏览源码的技巧…

如何使用GAP-Burp-Extension扫描潜在的参数和节点

关于GAP-Burp-Extension GAP-Burp-Extension是一款功能强大的Burp扩展,该工具在getAllParams扩展的基础上进行了升级,该工具不仅可以帮助广大研究人员在安全审计过程中扫描潜在的参数,而且还可以搜索潜在的链接并使用这些参数进行测试&#…

HarmonyOS—代码Code Linter检查

Code Linter代码检查 Code-Linter针对ArkTS/TS代码进行最佳实践、编程规范方面的检查,目前还会检查ArkTS语法规则。开发者可根据扫描结果中告警提示手工修复代码缺陷,或者执行一键式自动修复,在代码开发阶段,确保代码质量。 检查…

Linux之项目部署与发布

目录 一、Nginx配置安装(自启动) 1.一键安装4个依赖 2. 下载并解压安装包 3. 安装Nginx 4. 启动 nginx 服务 5. 对外开放端口 6. 配置开机自启动 7.修改/etc/rc.d/rc.local的权限 二、后端部署tomcat负载均衡 1. 准备2个tomcat 2. 修改端口 3…

【Vue3】学习watch监视:深入了解Vue3响应式系统的核心功能(上)

💗💗💗欢迎来到我的博客,你将找到有关如何使用技术解决问题的文章,也会找到某个技术的学习路线。无论你是何种职业,我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章,也欢…

基于Java的艺培管理解决方案

✍✍计算机毕业编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java、…

抖音小程序获取手机号

1、* 手机号获取和登录需要分开 &#xff08;规定&#xff09; 2、 抖音小程序首先得先通过试运营 没有通过试运营的 会提示没有权限 getPhoneNumber:fail auth deny 3、上代码 <button class"phone toutiaoSq" v-if"!userInfo.phone && isLogin&…

[AutoSar]BSW_Com03 DBC详解 (一)

目录 关键词平台说明一、DBC 定义1.1 相关工具 二、主要组成部分介绍2.1 Networks2.2 ECUs2.3 Network nodes2.4 messages2.5 signal2.6 Value Tables 三、主要组成部分关系图 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector &am…

本地项目如何上传到gitee

文章目录 一、在gitee上新建远程仓库二、初始化本地仓库三、执行git命令上传代码 一、在gitee上新建远程仓库 仓库名称必填&#xff0c;路径自动跟仓库名称保持一致 解释说明&#xff1a; 仓库名称&#xff1a;必填&#xff0c;每个仓库都需要有一个名称&#xff0c;同一个码…

tkinterFrame框架+标签框架LabelFrame+Toplevel窗口的使用

1.在tkinter中&#xff0c;Frame是一个容器小部件用于组织和管理其他小部件。它可以作为一个独立的可见区域&#xff0c;也可以作为其他小部件的父容器。 import tkinter as tk import tkinter.ttk as ttk import tkinter.messagebox as mbm tk.Tk() m.title("tkinter L…

Vue事件处理之v-on

1. 使用及定义 定义方法 function 方法名称(接受的event或是什么都不写) {//不管方法后括号内写与不写event,都可以接受到方法内表达式 }//定义一个接受参数的方法,此时也会在传入event function 方法名称(传入参数) {//可接受传入参数与event方法内表达式 } //定义一个接受参…

postgresql远程连接问题

修改pg_hba.conf文件&#xff0c;在文件末尾追加 host all all 0.0.0.0/0 md5

查看mysql数据库的版本

要查看MySQL数据库的版本&#xff0c;可以使用以下几种方法&#xff1a; 命令行&#xff08;已连接到MySQL服务器&#xff09;&#xff1a; 登录到MySQL服务器后&#xff0c;在MySQL提示符下执行&#xff1a; mysql> SELECT VERSION(); 或者&#xff0c;也可以执行 STATUS; …

啤酒:精酿啤酒与烧烤的热烈碰撞

在夏日的傍晚&#xff0c;烧烤与啤酒总是绝配。当Fendi Club啤酒遇上烧烤&#xff0c;它们将为我们带来一场热烈的美味碰撞。 Fendi Club啤酒&#xff0c;以其醇厚的口感和淡淡的麦芽香气而著称。这款啤酒在酿造过程中采用了特别的工艺&#xff0c;使得酒体呈现出诱人的金黄色&…

《业务建模驱动的企业架构转型白皮书》

当前&#xff0c;我国金融等国民经济重点行业和企业的数字化转型&#xff0c;仍存在战略落地难、业务技术协同难以及投入产出匹配难等问题&#xff0c;亟需通过实施企业架构&#xff0c;从顶层设计出发&#xff0c;制定符合自身需要的转型战略&#xff1b;从全局视角出发&#…

【JavaSE】集合框架

目录 程序场景分析 Java集合框架包含的内容List接口ArrayListLinkedListList接口的常用方法ArrayList案例背景分析代码示例扩展以下功能代码示例 LinkedList案例背景分析代码示例LinkedList的特殊方法 ArrayList与LinkedList对比 Set接口HashSet 集合的特点常用方法案例背景分析…

日志系统项目(2)项目实现(实用工具类、日志等级类、日志消息类、日志格式化输出类)

前面的文章中我们讲述了日志系统项目的前置知识点&#xff0c;再本文中我们将开始日志项目的细节实现。 日志系统框架设计 本项目实现的是一个多日志器日志系统&#xff0c;主要实现的功能是让程序员能够轻松的将程序运行日志信息落地到指定的位置&#xff0c;且支持同步与异…

成都直播基地作为产业重要载体,引领直播行业健康、多元发展

近年来&#xff0c;我国网络直播行业呈现出井喷式的发展态势。众多直播平台如雨后春笋般涌现&#xff0c;直播内容丰富多样&#xff0c;涵盖游戏、电竞、美食、旅游、教育等多个领域。同时&#xff0c;成都直播产业园规模持续扩大&#xff0c;产业不断完善&#xff0c;整体呈现…

常见的音频与视频格式

本专栏是汇集了一些HTML常常被遗忘的知识&#xff0c;这里算是温故而知新&#xff0c;往往这些零碎的知识点&#xff0c;在你开发中能起到炸惊效果。我们每个人都没有过目不忘&#xff0c;过久不忘的本事&#xff0c;就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…

蓝桥杯算法 一.

分析&#xff1a; 本题记录&#xff1a;m个数&#xff0c;异或运算和为0&#xff0c;则相加为偶数&#xff0c;后手获胜。 分析&#xff1a; 369*99<36500&#xff0c;369*100>36500。 注意&#xff1a;前缀和和后缀和问题
最新文章