Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用线程帮助解析大文件_Python_Multithreading_Parsing - Fatal编程技术网

Python 如何使用线程帮助解析大文件

Python 如何使用线程帮助解析大文件,python,multithreading,parsing,Python,Multithreading,Parsing,好的,这个文件是410k行代码。现在我在1.4秒内解析它,但我需要更快。但是这个文件有一些奇怪的地方 该文件的结构如下(感谢ARM): 基本上,我将所有这些解析到一个映射中,其中键是结构的名称,在这种情况下,由于ARM生成警告,因此可以复制。本例中的值是后面的字段 是否有一种方法可以使用线程将任务拆分为多个线程,将数据添加到同一个映射中 顺便说一句,我不是在找人帮我做这件事,我只是提供了一个文件结构的示例,这样你就会明白我不能只处理每一行,而是根据结构从[start:finish]开始处理 根据

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

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

是否有一种方法可以使用线程将任务拆分为多个线程,将数据添加到同一个映射中

顺便说一句,我不是在找人帮我做这件事,我只是提供了一个文件结构的示例,这样你就会明白我不能只处理每一行,而是根据结构从[start:finish]开始处理

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

; 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

您最好优化您的解析器代码,或者用另一种语言编写它

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

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

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

  • 找到文件的大小,并将其除以任务数(见下文)
  • 为每个任务指定一个字节范围:
    [任务编号*任务大小,任务编号*任务大小)
  • 每个任务执行以下操作:
  • 打开文件(这样每个任务都有自己的文件描述符)
  • 搜索到起始字节位置
  • 读取并丢弃,直到行尾
  • 读取行,丢弃行,直到找到节的开头
  • 循环:
  • 解析一个部分
  • 一直读到下一节开头的第一行
  • 如果起始行中第一个字符的位置在 范围,继续循环
  • 报告结果

  • 这个简单算法的问题在于,它假设解析的成本与解析的字符数成严格的比例,并且所有线程都将以相同的速度执行。因为这两种假设都不可能,所以很有可能一些线程会比其他线程先完成,然后旋转t继承人的车轮等待更多的工作


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

    必须看到您正在做的示例,很可能线程化不会有帮助,因为stock Python至少有GIL解释器要处理。So除非您在后端使用队列执行异步C调用。可能是运气不好。您可能能够将其重构为映射/减少问题,但没有示例代码。真倒霉,joe!最好在问题中插入一个文件示例。外部链接很脆弱,有时难以访问。GIL只会造成伤害I/O绑定的工作负载很好。CPU-I/O绑定的工作负载确实存在吉尔问题。您可能需要对代码进行配置。如果出现CPU绑定,Pypy可能会帮助相当多,如NUMBA或Cython。如果I/O绑定,请使用CPYTHON,并考虑MMAP之类的东西。这就是我计划要做的。还考虑通过
    multiprocessing.cpu\u count()进行潜水
    并指定一个进程来解析每个字节范围。这会更好吗?还是python多处理对于解析这样简单的事情需要太多的开销?@ZWiki:我想我在回答中已经很清楚了,python多处理比高效解析带来的开销更大。我将返回并强调这些词。啊,我错过了是的,主要的问题是这些“部分”不正确