【发布时间】:2017-02-12 16:10:31
【问题描述】:
我有一个包含超过 300 万行项目的 tsv 文件。每个 Item 都有一个 id、group 和一个 url,并且对 group 列进行了排序。
即
x1 gr1 {some url}/x1.jpg
x2 gr1 {some url}/x2.jpg
x3 gr2 {some url}/x1.jpg
我将它加载到 python 脚本中,并且需要在将这些项目加载到数据库之前检查组中所有项目的 url 的状态 200 OK。我想过使用流程并对每个流程进行 URL 检查,(我对此没有太多经验,因此不确定这是否是个好主意)
我的逻辑 atm:用 gr1 填充数组 a1 -> 将 a1 中的每个项目传递给一个新进程 -> 该进程检查 200 -> 如果没问题,将其放入数组 a2 -> 检查 a1 中的所有项目将 a2 推送到数据库(连同其他东西)-> 重复
这需要 30 分钟才能处理 100,000 个项目。瓶颈是 URL 检查。相比之下,如果不检查 URL,脚本就快如闪电了。到目前为止:
import csv
import re
import requests
import multiprocessing
from pymongo import MongoClient
import sys
#Load in Data
f = open('../tsvsorttest.tsv', 'rb')
reader = csv.reader(f, delimiter='\n')
#Get the first group name
currGroup = re.split(r'\t', next(reader)[0].decode('utf8'))[1]
currGroupNum = 0
items = []
checkedItems = []
#Method that checks the URL, if its 200, add to newItems
def check_url(newitem):
if requests.get(newitem['image_url']).status_code is 200:
print('got an ok!')
checkedItems.append(newitem)
global num_left
num_left -= 1
def clear_img(checkitems):
for thisItem in checkitems:
p = multiprocessing.Process(target=check_url(thisItem))
p.start()
#Start the loop, use i to keep track of the iteration count
for i, utf8_row in enumerate(reader):
unicode_row = utf8_row[0].decode('utf8')
x = re.split(r'\t', unicode_row)
item = {"id": x[0],
"group": x[1],
"item_url": x[2]
}
if currGroup != x[1]:
y = len(items)
print('items length is ' + str(y))
#Dont want single item groups
if y > 1:
print 'beginning url checks'
num_left = len(items)
clear_img(items)
while num_left is not 0:
print 'Waiting'
num_left = 0
batch = {"vran": currGroup,
"bnum": currGroupNum,
"items": newItems,
}
if len(checkedItems) > 0:
batches.insert_one(batch)
currGroupNum += 1
currGroup = x[1]
items = []
checkedItems = []
items.append(item)
if i % 100 == 0:
print "Milestone: " + str(i)
print "done"
其他注意事项:将原始 Tsv 拆分为 30 个单独的 tsv 文件并并行运行批处理脚本 30 次。这会有所不同吗?
【问题讨论】:
-
如果图像是从“普通”网络服务器请求的,您可以执行 HEAD 而不是 GET 请求。
-
啊,是的,这应该会有所帮助,我会试一试的。
-
从 Web 服务器获取响应的异步特性不太适合多处理库,该库更多地针对跨 CPU 内核分配任务。您可能希望大幅增加工作池的大小,以允许您在此处遇到的所有 I/O 绑定阻塞。
-
顺便说一句,Python 中的 for 循环相当慢。如果效率是重中之重,我建议用 C/C++ 实现它,然后用 Python 包装它。根据您想要(并且可以获得)的优化级别,您可能还可以使用并行循环。例如这里是an example of an OMP for loop using
curl可以与this 组合来检索状态码。
标签: python python-2.7 for-loop optimization