如何使用线程来帮助解析大型fi

2024-05-19 15:52:59 发布

您现在位置:Python中文网/ 问答频道 /正文

好的,这个文件是410k行代码。现在我只需1.4秒就能解析它,但我需要它更快。但是这个文件有一些奇怪的地方。。。在

文件的结构如下(感谢ARM):ARM fromelf
基本上,我将所有这些解析到一个映射中,其中的键是结构的名称,在这种情况下,由于ARM生成警告,可以复制这些映射。本例中的值是后面的字段。在

有没有一种方法可以使用线程将任务分成多个线程,将数据添加到同一个映射中?在

注:不是找人帮我做这件事,我只是提供了一个文件结构的例子,这样你就会明白我不能只处理每一行,而是要处理[开始:结束]以结构为基础。在

根据请求,我正在分析的示例:

; Structure, Table , Size 0x104 bytes, from inputfile.cpp
|Table.TableSize|                        EQU    0        ;  int
|Table.Data|                             EQU    0x4      ;  array[64] of MyClassHandle
; End of Structure Table

; Structure, Box2 , Size 0x8 bytes, from inputfile.cpp
|Box2.|                                  EQU    0        ;  anonymous
|Box2..|                                 EQU    0        ;  anonymous
|Box2...Min|                             EQU    0        ;  Point2
|Box2...Min.x|                           EQU    0        ;  short
|Box2...Min.y|                           EQU    0x2      ;  short
|Box2...Max|                             EQU    0x4      ;  Point2
|Box2...Max.x|                           EQU    0x4      ;  short
|Box2...Max.y|                           EQU    0x6      ;  short
; Warning: duplicate name (Box2..) present in (inputfile.cpp) and in (inputfile.cpp)
; please use the --qualify option
|Box2..|                                 EQU    0        ;  anonymous
|Box2...Left|                            EQU    0        ;  unsigned short
|Box2...Top|                             EQU    0x2      ;  unsigned short
|Box2...Right|                           EQU    0x4      ;  unsigned short
|Box2...Bottom|                          EQU    0x6      ;  unsigned short
; End of Structure Box2

; Structure, MyClassHandle , Size 0x4 bytes, from inputfile.cpp
|MyClassHandle.Handle|                   EQU    0        ;  pointer to MyClass
; End of Structure MyClassHandle

; Structure, Point2 , Size 0x4 bytes, from defects.cpp
|Point2.x|                               EQU    0        ;  short
|Point2.y|                               EQU    0x2      ;  short
; End of Structure Point2

; Structure, __fpos_t_struct , Size 0x10 bytes, from C:\Program Files\DS-5\bin\..\include\stdio.h
|__fpos_t_struct.__pos|                  EQU    0        ;  unsigned long long
|__fpos_t_struct.__mbstate|              EQU    0x8      ;  anonymous
|__fpos_t_struct.__mbstate.__state1|     EQU    0x8      ;  unsigned int
|__fpos_t_struct.__mbstate.__state2|     EQU    0xc      ;  unsigned int
; End of Structure __fpos_t_struct

END

Tags: offromsizebytesstructurecppstructend
1条回答
网友
1楼 · 发布于 2024-05-19 15:52:59

优化解析器代码或者用其他语言编写可能会更好。在

在标准的Python实现(“CPython”)中,有效地进行多进程的唯一方法是使用multiprocessing模块,它依赖于使用多个unix进程而不是线程(由于全局解释器锁,线程对于计算绑定的任务来说实际上是不可能的)。您可以使用共享内存对象甚至共享字典(请参见Managers),但基本上进程间通信非常昂贵,并且很快就会消耗多任务处理的优势。在

如果您的各个线程在解析期间不需要关于结构的全局信息,那么它们可以各自创建自己的字典,然后您可以在最后合并所有的字典。将一个(可选择的)Python对象从一个进程发送到另一个进程是很容易的,但是请考虑以下问题:您的任务是解析文本表示并创建内部表示。pickle和unpickle对象包括获取一个内部表示,从中生成一个字符串,然后在通信通道的另一端解析该字符串。换句话说,您的解析任务只会生成另一个解析任务,并为序列化带来一些额外的开销。除了unpickler可能是比您编写的更快的解析器之外,这不太可能是一个很大的胜利。这让我们回到优化解析器的问题上来。在

并行化问题的一部分通常是直截了当的,那就是在进程之间划分任务。假设要解析的块(start:finish)不是太大,也就是说,410k行由几千个这样的子任务组成,那么有一个简单的策略:

  1. 找到文件的大小,然后除以任务数(见下文)
  2. 给每个任务一个字节范围:[task_number * task_size, task_number * task_size)。在
  3. 每个任务执行以下操作:
    1. 打开文件(这样每个任务都有自己的文件描述符)
    2. 搜索到起始字节位置
    3. 阅读并丢弃,直到行尾
    4. 读取行,丢弃它们直到找到一个节的开头。在
    5. 循环:
      1. 解析节。在
      2. 读到下一节开始的第一行。在
      3. 如果起始行中第一个字符的位置在 范围,继续循环。在
    6. 报告结果

这个简单算法的问题在于,它假定解析的开销与解析的字符数严格成正比,并且所有线程都将以相同的速度执行。因为这两种假设都不太可能,所以很有可能有些线程会比其他线程完成得更快,然后只会旋转轮子等待更多的工作。在

这可以通过将文件拆分成更小的部分来避免,并在每个线程完成正在处理的线程时获得下一个可用的部分。(当然,您必须协调工作队列,但这只是每个工作块的一个同步,这不是太多的开销。)但是,我不建议上面这样做,因为输入文件不是太大,可以分成非常小的部分。由于实际工作的开始和结束都需要通过实际扫描来找到,因此每个工作块都有一些相关的开销并且块越多,开销就越大。如果块足够小,就会有一些根本没有实际工作。正确地调整参数需要更多关于工作单元大小的知识,而不是问题所揭示的。在

相关问题 更多 >