gpt4 book ai didi

python - 在 Python 中并行处理一组 XML 文件

转载 作者:太空宇宙 更新时间:2023-11-03 20:23:34 24 4
gpt4 key购买 nike

我需要处理一组(~20)相对较大(20-300MB)的 XML 文件(下面的截断示例),并且我正在寻找一种加快速度的方法。

这些文件包含“事件”(此处称为“数据集”),具有多个相关属性,最重要的是 UID。每个 UID 通常有多个事件。

我有一个唯一的 UID 列表,我想为每个 UID 查找事件并提取 UTCtime 属性。并行化的最佳方法是什么?

我尝试过使用线程(见下文),但它没有带来任何明显的加速。我还尝试了多重处理,但我需要在进程之间传递 XML 元素,但收到有关元素不可“pickleable”的错误。

谢谢

使用线程的 Python 方法

    import lxml.etree as et, threading,concurrent.futures, datetime as dt

uidList = ['B0 2B 5C 05 09 00 12 E0',
'B0 2A 5C 05 09 00 12 E0',
'AD 2A 5C 05 09 00 12 E0',
'4F 2D 5C 05 09 00 12 E0']

uidList_split = [uidList[0:2],uidList[2:4]]

xPathFmt = 'Dataset/[UID = "{:s}"]'
timeFmt = '%m/%d/%Y %H:%M:%S.%f'

def thread_function(i):
scanTimes = {}
for uid in uidList_split[i]:
scanTimes[uid] = []
for e in root.iterfind(xPathFmt.format(uid)):
scanTimes[uid].append(dt.datetime.strptime(e.findtext('UTCTime'),timeFmt))
return(scanTimes)

tree = et.parse('test.xml')
root = tree.getroot()

with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
scanTimes = list(executor.map(thread_function, range(2)))

scanTimes = {k: v for d in scanTimes for k, v in d.items()}

for uid in scanTimes: print(uid,scanTimes[uid])

示例 XML 文件

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Datasets>
<Dataset>
<UTCTime>05/31/2019 03:44:27.737</UTCTime>
<ReaderID>44252</ReaderID>
<Address>1</Address>
<UID>B0 2B 5C 05 09 00 12 E0</UID>
<ScanCount>1</ScanCount>
<Type>177</Type>
</Dataset>
<Dataset>
<UTCTime>05/12/2019 02:46:22.737</UTCTime>
<ReaderID>44252</ReaderID>
<Address>1</Address>
<UID>B0 2B 5C 05 09 00 12 E0</UID>
<ScanCount>1</ScanCount>
<Type>177</Type>
</Dataset>
<Dataset>
<UTCTime>05/31/2019 03:44:34.215</UTCTime>
<ReaderID>44251</ReaderID>
<Address>2</Address>
<UID>B0 2A 5C 05 09 00 12 E0</UID>
<ScanCount>1</ScanCount>
<Type>177</Type>
</Dataset>
<Dataset>
<UTCTime>05/31/2019 04:16:56.957</UTCTime>
<ReaderID>44252</ReaderID>
<Address>1</Address>
<UID>AD 2A 5C 05 09 00 12 E0</UID>
<ScanCount>1</ScanCount>
<Type>177</Type>
</Dataset>
<Dataset>
<UTCTime>05/31/2019 04:05:07.705</UTCTime>
<ReaderID>44252</ReaderID>
<Address>1</Address>
<UID>4F 2D 5C 05 09 00 12 E0</UID>
<ScanCount>1</ScanCount>
<Type>177</Type>
</Dataset>
</Datasets>```

最佳答案

我认为您是否进行了大量查找,例如正如您所说的数千,您应该花一些时间将数据放入更好的搜索结构中。因此,我建议将 XML 解析为“内存中”数据结构,然后从内存中进行查找。您可能认为这会占用太多 RAM,但如果您查看 XML 文件中的典型数据集条目,您会发现它大约有 220 字节,而您实际上只需要大约 30 字节的 UTCTime 和 UID,所以它会缩小约 7 倍。

我想出了两种方法...

第一个使用 xmltodict 并将 XML 文件加载到 Python dict 中。在我的 Mac 上加载一个 200MB 的虚拟 XML 文件大约需要 18 秒,但随后的每次查找只需要 3 微秒。它的优点是它是一个标准的、经过测试的 XML 阅读器,因此它应该很健壮,但它存储了您可能不需要的内容,因此占用的内存较多。

第二种方法只是使用 Python 正则表达式解析 XML。它的速度大致相同,但占用的内存更少,但鲁棒性可能较差。

#!/usr/bin/env python3

def method1():

import xmltodict

with open('file.xml') as fd:
XML = xmltodict.parse(fd.read())

# Lookup a UID
for Dataset in XML['Datasets']['Dataset']:
if Dataset['UID'] == "31 1e 24 81 82 71 6f 1d":
print(Dataset)

def method2():

import re

# Compile the regex to look for UID and UTCTime for better performance
UIDre = re.compile("<UID>(.*)</UID>")
UTCTimere = re.compile("<UTCTime>(.*)</UTCTime>")

# Parse XML building a dict, indexed by UID, of lists of matching times
d = {}
with open('file.xml') as fp:
for lineno, line in enumerate(fp):
result = re.search(UIDre,line)
if result != None:
UID = result.group(1)
#print(f"UID:{UID}")
if not UID in d:
d[UID] = []
d[UID].append(UTCTime)
continue
result = re.search(UTCTimere,line)
if result != None:
UTCTime = result.group(1)
#print(f"UTCTime:{UTCTime}")

# Do a lookup
print(d["31 1e 24 81 82 71 6f 1d"])

method1()
method2()
<小时/>

如果其他人喜欢测试理论或方法,这里是我用来生成包含 1,000,000 个虚拟数据集的 200MB XML 文件的代码:

#!/usr/bin/env python3

import random

print('<?xml version="1.0" encoding="utf-8" standalone="no"?>')
print('<Datasets>')
for d in range(1000000):
ReaderID = random.randrange(65536)
UID = "%02x" % random.randrange(256)
UID+= " %02x" % random.randrange(256)
UID+= " %02x" % random.randrange(256)
UID+= " %02x" % random.randrange(256)
UID+= " %02x" % random.randrange(256)
UID+= " %02x" % random.randrange(256)
UID+= " %02x" % random.randrange(256)
UID+= " %02x" % random.randrange(256)

Type = random.randrange(65536)
print(f"<Dataset>")
print(f" <UTCTime>05/31/2019 04:05:07.705</UTCTime>")
print(f" <ReaderID>{ReaderID}</ReaderID>")
print(f" <Address>1</Address>")
print(f" <UID>{UID}</UID>")
print(f" <ScanCount>1</ScanCount>")
print(f" <Type>{Type}</Type>")
print(f"</Dataset>")

print('</Datasets>')

然后,出于测试目的,我使用常规编辑器手动将代码中的 UID 植入到 XML 文件中。

关于python - 在 Python 中并行处理一组 XML 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57993579/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com