【python】多线程、多进程性能比较

测试样例:复制3部电影,每部大小为2.04G,比较复制耗时

1.单进程单线程

import os
import threading
import datetime

t0 = datetime.datetime.now()

source_dir = "F:\多线程测试\origin"
dest_dir = "F:\多线程测试\copy"

# 3.读取源文件夹的文件列表
file_list = os.listdir(source_dir)

# 4.遍历文件列表实现拷贝
for file_name in file_list:

    print(file_name, "--拷贝的进程pid是:", os.getpid())
    print(file_name, "--拷贝的线程是:", threading.current_thread())
    # 1.拼接源文件路径和目标文件所在的路径
    source_path = source_dir + "/" + file_name
    dest_path = dest_dir + "/" + file_name

# 2.打开源文件和目标文件
    with open(source_path, "rb") as source_file:
        with open(dest_path, "wb") as dest_file:
            # 3.循环读取源文件到目标路径
            while True:
                data = source_file.read(1024)
                if data:
                    dest_file.write(data)
                else:
                    break

print(datetime.datetime.now()-t0)

1_同学麦娜丝.mkv --拷贝的进程pid是: 18016
1_同学麦娜丝.mkv --拷贝的线程是: <_MainThread(MainThread, started 308)>
2_同学麦娜丝.mkv --拷贝的进程pid是: 18016
2_同学麦娜丝.mkv --拷贝的线程是: <_MainThread(MainThread, started 308)>
3_同学麦娜丝.mkv --拷贝的进程pid是: 18016
3_同学麦娜丝.mkv --拷贝的线程是: <_MainThread(MainThread, started 308)>
0:03:21.734185

2.多线程

import threading
import os
import datetime

def copy_file(file_name, source_dir, dest_dir):
    print(file_name, "--拷贝的进程pid是:", os.getpid())
    print(file_name, "--拷贝的线程是:", threading.current_thread())
    # 1.拼接源文件路径和目标文件所在的路径
    source_path = source_dir + "/" + file_name
    dest_path = dest_dir + "/" + file_name
    # 2.打开源文件和目标文件
    with open(source_path, "rb") as source_file:
        with open(dest_path, "wb") as dest_file:
            # 3.循环读取源文件到目标路径
            while True:
                data = source_file.read(1024)
                if data:
                    dest_file.write(data)
                else:
                    break


if __name__ == '__main__':
    t0 = datetime.datetime.now()

    # 1.定义源文件夹和目标文件夹
    source_dir = "F:\多线程测试\origin"
    dest_dir = "F:\多线程测试\copy"

    # 2.创建目标文件夹
    try:
        os.mkdir(dest_dir)
    except:
        print("目标文件夹已经存在!")

    # 3.读取源文件夹的文件列表
    file_list = os.listdir(source_dir)

    # 4.遍历文件列表实现拷贝
    for file_name in file_list:
        # copy_file(file_name, source_dir, dest_dir)
        # 5.使用多线程实现多任务拷贝
        sub_thread = threading.Thread(target=copy_file,
                                      args=(file_name, source_dir, dest_dir))
        sub_thread.start()
        sub_thread.join()
        print(datetime.datetime.now()-t0)

1_同学麦娜丝.mkv --拷贝的进程pid是: 17212
1_同学麦娜丝.mkv --拷贝的线程是: <Thread(Thread-1, started 18420)>
0:01:05.723885
2_同学麦娜丝.mkv --拷贝的进程pid是: 17212
2_同学麦娜丝.mkv --拷贝的线程是: <Thread(Thread-2, started 10608)>
0:02:11.567183
3_同学麦娜丝.mkv --拷贝的进程pid是: 17212
3_同学麦娜丝.mkv --拷贝的线程是: <Thread(Thread-3, started 20368)>
0:03:20.944711

3.多进程

import multiprocessing
import os
import datetime


def copy_file(file_name, source_dir, dest_dir):
    print(file_name, "--拷贝的进程pid是:", os.getpid())
    # 1.拼接源文件路径和目标文件所在的路径
    source_path = source_dir + "/" + file_name
    dest_path = dest_dir + "/" + file_name
    # 2.打开源文件和目标文件
    with open(source_path, "rb") as source_file:
        with open(dest_path, "wb") as dest_file:
            # 3.循环读取源文件到目标路径
            while True:
                data = source_file.read(1024)
                if data:
                    dest_file.write(data)
                else:
                    break


if __name__ == '__main__':

    t0 = datetime.datetime.now()

    # 1.定义源文件夹和目标文件夹
    source_dir = "F:\多线程测试\origin"
    dest_dir = "F:\多线程测试\copy"

    # 2.创建目标文件夹
    try:
        os.mkdir(dest_dir)
    except:
        print("目标文件夹已经存在!")

    # 3.读取源文件夹的文件列表
    file_list = os.listdir(source_dir)

    # 4.遍历文件列表实现拷贝
    for file_name in file_list:
        # copy_file(file_name, source_dir, dest_dir)
        # 5.使用多进程实现多任务拷贝
        sub_process = multiprocessing.Process(target=copy_file,
                                              args=(file_name, source_dir, dest_dir))
        sub_process.start()
        sub_process.join()
        print(datetime.datetime.now() - t0)

1_同学麦娜丝.mkv --拷贝的进程pid是: 17280
0:01:30.373696
2_同学麦娜丝.mkv --拷贝的进程pid是: 21340
0:02:51.638254
3_同学麦娜丝.mkv --拷贝的进程pid是: 14360
0:04:03.929954

比较:

方式耗时
单进程单线程0:03:21
单进程多线程0:03:20
多进程0:04:03

在这个测试样例中,多进程最为耗时,可能的原因是多进程上下文切换更为耗时,同时本场景不属于CPU密集场景,并不适合多进程;单进程多线程和单进程单线程的耗时差不多,是我没想到的,感觉没有发挥出多线程的优势来,原因可能是本场景不涉及到CPU计算,纯IO密集,能提高的空间有限?也可能是复制的电影数量少了?
我尝试将复制的电影数量提高到6个,观察两种方式的耗时变化

方式耗时
单进程单线程0:07:37
单进程多线程0:07:40

好像不符合期望

代码参考:https://blog.csdn.net/weixin_44917390/article/details/119610760?spm=1001.2014.3001.5506(很不错)

————————————————————
2022.10.30.更新:
Python的多线程不是真正的多线程,因为GIL的原因,同一时间只能有一个线程在执行,哪怕时多核,换句话说,就算是十核的CPU执行多线程,也只能用到一个核,此时就是单核多线程。对比JAVA,多个线程能分发在多个核上同时运行(线程数≤核数)。
Python要想利用多核怎么办呢?
方法一:多进程。
方法二:将计算密集型任务用C语言来写,然后用Python来调用。
多说一句:C语言这类“很快”的语言最适合的就是计算密集型任务,在I/O密集任务上相比Python并没有绝对的优势。

那么Python的多线程还有用武之地吗?
在爬虫,web应用等I/O密集场景,还是有效果的。因为多线程的本质是避免CPU闲置浪费,此时就算单核多线程也能充分利用它的性能。

参考:
https://www.zhihu.com/question/23474039/answer/269526476?utm_source=wechatMessage_answer_bottom

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值