Python 性能优化|多线程读取文件

这篇具有很好参考价值的文章主要介绍了Python 性能优化|多线程读取文件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

分析结论

多进程可以实现逐行遍历同一个文件(可以保证每一个进程遍历的行都是完整且互不重复的),且可以提高遍历性能。

多进程 / 多线程遍历文件速度
  1. 单进程、多线程读取同一个文件时,每个线程的运行时间并不能随线程数的增加的降低;
  2. 多进程读取同一个文件时,每个进程的运行时间随线程数的增加而降低。
进一步优化方法

通过统计读取到的字符串长度,计算当前文件指针位置,从而避免在每次遍历中均需使用 file.tell() 获取当前文件指针位置。

分析过程

构造 11202 MB、691130 行的测试数据。具体测试数据特征如下:

  • 文件大小:11746098941 Bytes(11202 MB)
  • 行数:691130
import time
1. 单进程、单线程遍历文件
t1 = time.time()
with open(path, "r", encoding="UTF-8") as file:
    for _ in file:
        pass
t2 = time.time()
print(t2 - t1)

运行时间:21.79 秒(三次测试 23.55、20.84、21.00 取平均值)

2. 多线程遍历文件
import os
from theading import Thread

定义每个线程 / 进程的遍历函数如下:通过捕获 UnicodeDecodeError 异常,避免出现刚好切分到半个字的情况;通过在遍历前先 file.readline(),使每一个切分点中尚未结束的行一定归属上一进程 / 线程而不是下一进程 / 线程,从而保证每一个进程 / 线程遍历的每一行都是完整且互不重复的。

def read(path, start, end):
    """每个进程 / 线程的遍历函数

    Parameters
    ----------
    path : str
        文件路径
    start : int
        本分块的开始位置
    end : int
        本分块的结束位置
    """
    cnt = 0
    with open(path, "r", encoding="UTF-8") as file:
        file.seek(start)  # 移动到目标位置
        if start != 0:
            while True:
                try:
                    file.readline()  # 跳过当前行(所有未遍历完的行属于上一段)
                    break
                except UnicodeDecodeError:  # 刚好切分到半个字,向后移动一个字符
                    file.seek(start + 1)
        while file.tell() <= end:
            file.readline()
            cnt += 1

定义多线程遍历函数:

def multi_thread_load_csv(path: str, n_thread: int):
    """多线程遍历函数"""
    size = os.path.getsize(path)  # 获取文件大小用于分块
    thread_lst = []
    for i in range(n_thread):
        s = size // n_thread * i  # 计算当前分块开始位置
        e = size // n_thread * (i + 1)  # 计算当前分块结束位置
        thread = Thread(target=read, args=(s, e))
        thread.start()
        thread_lst.append(thread)

    for thread in thread_lst:
        thread.join()

测试线程数为 1 - 10 之间的读取时间,每种线程数测试 10 次,测试代码及结果如下:

import numpy as np

for k in range(1, 11):
    use_time = []
    for _ in range(10):
        t1 = time.time()
        multi_thread_load_csv("/home/txjiang/archive_analysis/gather_detail.txt", k)
        t2 = time.time()
        use_time.append(t2 - t1)
        print(f"线程={k} 平均时间={np.average(use_time)} 标准差={np.std(use_time)}")
线程数 用时的平均值 用时的标准差
1 49.0841 0.6299
2 53.2189 1.4267
3 53.5290 1.3273
4 56.4923 1.4843
5 56.6679 3.2745
6 56.5164 1.7789
7 58.2352 1.1148
8 58.2353 0.6817
9 60.9896 1.3365
10 64.2063 2.3251

因为在每一行的遍历中需要增加一次 file.tell(),所以单线程时的速度相较于直接读取会更慢。

3. 多进程遍历文件
from multiprocessing import Process

定义多进程遍历函数:

def multi_process_load_csv(path: str, n_process: int):
    """多进程遍历函数"""
    size = os.path.getsize(path)  # 获取文件大小用于分块
    process_lst = []
    for i in range(n_process):
        s = size // n_process * i  # 计算当前分块开始位置
        e = size // n_process * (i + 1)  # 计算当前分块结束位置
        process = Process(target=read, args=(s, e))
        process.start()
        process_lst.append(process)
    for process in process_lst:
        process.join()

测试线程数为 1 - 10 之间的读取时间,每种线程数测试 10 次,测试代码及结果如下:

import numpy as np

for k in range(1, 11):
    use_time = []
    for _ in range(10):
        t1 = time.time()
        multi_process_load_csv("/home/txjiang/archive_analysis/gather_detail.txt", k)
        t2 = time.time()
        use_time.append(t2 - t1)
        print(f"线程={k} 平均时间={np.average(use_time)} 标准差={np.std(use_time)}")
进程数 用时的平均值 用时的标准差
1 50.1561 0.8431
2 26.5089 0.5581
3 17.7663 0.2771
4 13.4338 0.3024
5 10.7654 0.2950
6 9.1950 0.3471
7 7.7160 0.1764
8 7.0321 0.1938
9 6.3484 0.2150
10 5.6354 0.1271
11 5.1283 0.2361
12 4.7841 0.0512
13 4.5149 0.2186
14 4.1525 0.0533
15 3.9554 0.1442
16 3.8481 0.1167
17 3.6455 0.0763
18 3.4030 0.0255
19 3.3732 0.2159
20 3.1933 0.0674
21 3.0091 0.0845
22 2.9235 0.0646
23 2.9474 0.2234
24 2.7500 0.0382
25 2.6592 0.0340
26 2.5687 0.0333
27 2.6273 0.3457
28 2.4343 0.0253
29 2.3647 0.0223
30 2.2572 0.0343

因为在每一行的遍历中需要增加一次 file.tell(),所以单进程时的速度相较于直接读取会更慢。文章来源地址https://www.toymoban.com/news/detail-699457.html

到了这里,关于Python 性能优化|多线程读取文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python爬虫:单线程、多线程、多进程

    在使用爬虫爬取数据的时候,当需要爬取的数据量比较大,且急需很快获取到数据的时候,可以考虑将单线程的爬虫写成多线程的爬虫。下面来学习一些它的基础知识和代码编写方法。 进程可以理解为是正在运行的程序的实例。进程是拥有资源的独立单位,而线程不是独立的

    2024年02月13日
    浏览(41)
  • 【python】13.进程和线程

    今天我们使用的计算机早已进入多CPU或多核时代,而我们使用的操作系统都是支持“多任务”的操作系统,这使得我们可以同时运行多个程序,也可以将一个程序分解为若干个相对独立的子任务,让多个子任务并发的执行,从而缩短程序的执行时间,同时也让用户获得更好的

    2024年01月17日
    浏览(41)
  • Python小姿势 - 线程和进程:

    线程和进程: Python里面线程是真正的并行执行,进程是可以并行执行的。 所谓进程,就是操作系统中执行一个程序的独立单元,它是系统进行资源分配和调度的基本单位。一个进程可以创建和撤销另一个进程,同一个进程内可以并发执行多个不同的子程序。 所谓线程,是进

    2024年02月01日
    浏览(43)
  • chatgpt赋能python:Python倒序for:如何优化循环遍历

    Python作为一门高级编程语言,一直以来都在开发者中得到广泛的应用。在日常的编程工作中,遍历列表(List)和元组(Tuple)是很常见的操作。而对于列表或元组的倒序遍历,开发者们可能还没有找到最优的解决方案。本文将分享一种高效的Python倒序for循环方式,让您的代码

    2024年02月07日
    浏览(51)
  • 【Python】多线程编程 ① ( 线程相关概念 | 进程 | 线程 | 协程 / 纤程 | 管程 )

    进程 与 操作系统 : 进程 是 操作系统 中 能够独立运行的单元 , 是 操作系统 对 正在运行的 应用程序 的 抽象结构 描述 ; 操作系统 中 运行的每个 应用程序 就是一个进程 ; 一个操作系统中可以运行 多个 进程 ; 每个 应用程序 都会被 操作系统 分配一个 进程 ID ; 多个进程之间

    2024年02月15日
    浏览(36)
  • python多进程与多线程

    1.1 GIL 全局解释器锁 其他语言,CPU是多核时是支持多个线程同时执行。但在Python中,无论是单核还是多核,同时只能由一个线程在执行。其根源是GIL的存在。GIL的全称是Global Interpreter Lock(全局解释器锁),来源是Python设计之初的考虑,为了数据安全所做的决定。某个线程想要执

    2024年02月05日
    浏览(39)
  • 8.0 Python 使用进程与线程

    python 进程与线程是并发编程的两种常见方式。进程是操作系统中的一个基本概念,表示程序在操作系统中的一次执行过程,拥有独立的地址空间、资源、优先级等属性。线程是进程中的一条执行路径,可以看做是轻量级的进程,与同一个进程中的其他线程共享相同的地址空间

    2024年02月13日
    浏览(40)
  • Python多任务教程:进程、线程、协程

    进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。进程是一种抽象的概念,从来没有统一的标准定义。进程一般由程序、数据集合和进程控制块三部分组成。程序用于描述进

    2024年02月12日
    浏览(39)
  • python-16-线程池和进程池python并发编程

    Python ThreadPoolExecutor线程池 线程池的基本原理是什么? 利用Python快速实现一个线程池,非常简单 Python并发编程专题 一、为什么要引入并发编程? 场景1:一个网络爬虫,按顺序爬取花了1小时,采用并发下载减少到20分钟! 场景2:一个APP应用,优化前每次打开页面需要3秒,采

    2024年02月04日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包