【发布时间】:2021-11-04 03:44:55
【问题描述】:
我有一个包含 2 个进程的 python 脚本:
- 过程 1:加载和解压缩文件
- 过程 2:处理文件,用它做一些事情。
在实施多处理之前,该软件似乎按时间顺序完成其工作。加载所有压缩文件,解压缩它们,然后打开它们来做一些事情。
所以我在游戏中引入了多处理,现在似乎在加载和解压缩文件的同时,打开和处理它们的过程已经开始。所以有多个进程同时做事。问题是,当我在大数据(超过 100 个文件)上运行此代码时,我遇到了并发文件访问的问题。这导致PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 当我在一个小数据集(大约 30 个文件)上运行 sn-p 时,它似乎没问题,因为文件在进程 2 开始时被解压缩得非常快。
我想要什么:我想保留多处理,因为它可以加快速度,但我希望只有在所有文件都已解压缩(例如,进程 1 已完成)时才启动进程 2。
这是我的 sn-p:
import os
import csv
import collections
import datetime
import zipfile
import re
import shutil
import fnmatch
from pathlib import Path
import ntpath
import configparser
from multiprocessing import Pool
def generate_file_lists():
# Change the following line to a real path
data_files = 'c:\desktop\DataEnergy'
pattern = '*.zip'
last_root = None
args = []
for root, dirs, files in os.walk(data_files):
for filename in fnmatch.filter(files, pattern):
if root != last_root:
last_root = root
if args:
yield args
args = []
args.append((root, filename))
if args:
yield args
def unzip(file_list):
"""
file_list is a list of (root, filename) tuples where
root is the same for all tuples.
"""
# Change the following line to a real path:
counter_part = 'c:\desktop\CounterPart'
for root, filename in file_list:
path = os.path.join(root, filename)
date_zipped_file_s = re.search('-(.\d+)-', filename).group(1)
date_zipped_file = datetime.datetime.strptime(date_zipped_file_s, '%Y%m%d').date()
#Create the new directory location
new_dir = os.path.normpath(os.path.join(os.path.relpath(path, start='c:\desktop\DataEnergy'), ".."))
#Join the directory names counter_part and create their paths.
new = os.path.join(counter_part, new_dir)
#Create the directories
if (not os.path.exists(new)):
os.makedirs(new)
zipfile.ZipFile(path).extractall(new)
#Get al the zipped files
files = os.listdir(new)
#Rename all the files in the created directories
for file in files:
filesplit = os.path.splitext(os.path.basename(file))
if not re.search(r'_\d{8}.', file):
os.rename(os.path.join(new, file), os.path.join(new, filesplit[0]+'_'+date_zipped_file_s+filesplit[1]))
# Required for Windows:
if __name__ == '__main__':
pool = Pool(13)
pool.map(unzip, generate_file_lists())
print('the files have been unzipped!')
#Start proces 2
all_missing_dates = ['20210701', '20210702']
missing_dates = [datetime.datetime.strptime(i, "%Y%m%d").date() for i in all_missing_dates]
dates_to_process = []
root = Path('.\middle_stage').resolve()
at_set = {'Audi', 'Mercedes', 'Volkswagen'}
#Only read the rows if they fulfill the following conditions.
def filter_row(r, missing_date):
if set(row).intersection(at_set):
if len(r) > 24 and r[24].isdigit():
aantal_pplgs = int(r[24])
date_time = datetime.datetime.fromisoformat(r[0]) if len(r) > 3 else True
condition_3 = date_time.date() == missing_date if len(r) > 3 else True
return condition_3
return False
#Open the files and read the rows
print("Start reading data")
data_per_date = dict()
for missing_date in missing_dates:
print("\tReading missing date: ", missing_date)
files=[fn for fn in (e for e in root.glob(f"**/*_{missing_date:%Y%m%d}.txt") if e.is_file())]
if len(files) != 13:
continue
dates_to_process.append(missing_date)
vehicle_loc_dict = collections.defaultdict(list)
for file in files:
with open(file, 'r') as log_file:
reader = csv.reader(log_file, delimiter = ',')
next(reader) # skip header
for row in reader:
if filter_row(row, missing_date):
print('filter_row has been executed!')
data_per_date[missing_date] = vehicle_loc_dict
【问题讨论】:
-
您需要使用锁定,在另一个进程仍在处理文件时锁定对文件的访问。您也可以使用队列系统,其中解压缩从压缩文件队列中提取,然后将其添加到要处理的队列等中,其他线程从该队列中提取。
-
@Booboo,这是我昨天和你谈过的地方。
-
@SeanPowell 这些是一些不错的选择,但是我不知道如何在上面的代码中实现它..
-
我添加了一个答案,可以让您大致了解如何实现此功能,如果您需要其他任何内容,请随时问我 :)
-
@Mediterráneo 我刚看到这个问题。我没有收到您的评论通知,因为我之前没有评论过 this 帖子;你应该在你之前的问题上写下这个评论,并附上这个新问题的链接。有机会我会深入研究。
标签: python concurrency multiprocessing yield