2015-10-08 2 views
0

Давайте предположим, что у меня есть текстовый файл с только 2 строки следующим образом:Python многопроцессорная: Чтение файла и обновление словаря

File.txt: 

100022441 @DavidBartonWB Guarding Constitution 
100022441 RT @frankgaffney 2nd Amendment Guy. 

Первый столбец идентификатор пользователя и второй столбец пользователь твит. Я хотел бы, чтобы прочитать выше текстовый файл и обновить следующий словарь:

d={'100022441':{'@frankgaffney': 0, '@DavidBartonWB': 0}}. 

Вот мой код:

def f(line): 
    data = line.split('\t') 
    uid = data[0] 
    tweet = data[1] 
    if uid in d.keys(): 
     for gn in d[uid].keys(): 
      if gn in tweet: 
       return uid, gn, 1 
      else: 
       return uid, gn, 0 
p = Pool(4) 
with open('~/File.txt') as source_file: 
    for uid, gn, r in p.map(f, source_file): 
     d[uid][gn] += r 

Поэтому в основном мне нужно прочитать каждую строку файла и определить, является ли пользователь находится в моем словаре, и если это так, то ли твит содержит ключи пользователя в словаре (например, «@frankgaffney» и «@DavidBartonWB»). Таким образом, на основе двух линий, которые я написал выше, код должен привести:

d = {{'100022441':{'@frankgaffney': 1, '@DavidBartonWB': 1 }} 

Но это дает:

d = {{'100022441':{'@frankgaffney': 1, '@DavidBartonWB': 0 }} 

По какой-то причине код всегда теряет один из ключей для всех пользователей. Любая идея, что не так в моем коде?

ответ

0

Ваш файл с разделителями табуляции, и вы всегда проверяете третья колонка для упоминания; он работает правильно для первого упоминания, потому что вы передаете весь файл функции, а не каждой строке. Так эффективно вы делаете это:

>>> s = '100022441\[email protected] Guarding Constitution\n100022441\[email protected] 2nd Amendment Guy.' 
>>> s.split('\t') 
['100022441', '@DavidBartonWB Guarding Constitution\n100022441', '[email protected] 2nd Amendment Guy.'] 

Я рекомендую два подхода:

  1. Карта ваша функция каждой линии в файле.
  2. Используйте регулярные выражения для более надежного поиска.

Попробуйте эту версию:

import re 

d = {'100022441':{'@frankgaffney': 0, '@DavidBartonWB': 0}} 
e = r'(@\w+)' 

def parser(line): 
    key, tweet = line.split('\t') 
    data = d.get(key) 
    if data: 
     mentions = re.findall(e, tweet) 
     for mention in mentions: 
      if mention in data.keys(): 
       d[key][mention] += 1 

with open('~/File.txt') as f: 
    for line in f: 
     parser(line) 

print(d) 

После того, как вы подтвердили его работать правильно, то вы можете многопроцессной его:

import itertools, re 
from multiprocessing import Process, Manager 

def parse(queue, d, m): 
    while True: 
     line = queue.get() 
     if line is None: 
      return # we are done with this thread 
     key, tweet = line.split('\t') 
     data = d.get(key) 
     e = r'(@\w+)' 
     if data: 
      mentions = re.findall(e, tweet) 
      for mention in mentions: 
       if mention in data: 
        if mention not in m: 
        m[mention] = 1 
        else: 
        m[mention] += 1 

if __name__ == '__main__': 
    workers = 2 
    manager = Manager() 

    d = manager.dict() 
    d2 = manager.dict() 
    d = {'100022441': ['@frankgaffney', '@DavidBartonWB']} 

    queue = manager.Queue(workers) 

    worker_pool = [] 
    for i in range(workers): 
     p = Process(target=parse, args=(queue, d, d2)) 
     p.start() 
     worker_pool.append(p) 

    # Fill the queue with data for the workers 
    with open(r'tweets2.txt') as f: 
     iters = itertools.chain(f, (None,)*workers) 
     for line in iters: 
      queue.put(line) 

    for p in worker_pool: 
     p.join() 

    for i,data in d.iteritems(): 
     print('For ID: {}'.format(i)) 
     for key in data: 
      print(' {} - {}'.format(key, d2[key])) 
+0

Большое спасибо за это отличное решение.Первый код работает отлично и довольно быстро по сравнению с моим. Но второй код (т. Е. Многопроцессорный) не работает. Он поддерживает работу ядра без использования процессора и никогда не останавливается даже для текстового файла с 2 строками. – msmazh

+0

Да, я написал выше в спешке и пропустил несколько вещей. Существует также [ошибка] (http://bugs.python.org/issue6766), которая предотвращает правильное обновление суб-словарей при использовании в многопроцессорной обработке. –

+0

Я обновил ответ с рабочей версией, у которой есть некоторые компромиссы, чтобы обойти ошибку [update update] (http://bugs.python.org/issue6766). –

0

второй столбец данных [1], а не данные [2]

тот факт, что данные [2] работы означает, что вы разбиением на слова, а не столбцы

, если вы хотите найти для пользовательский ключ как отдельное слово (в отличие от подстроки), вам нужно твит = данные [1:]

Если вы хотите найти подстроку, вам нужно разделить на две части: uid, tweet = line.split (Нет, 1)

+0

Да, но это была опечатка в копировании и вставляя мой код здесь. В исходном коде, который я написал, это правильно, потому что в моем файле больше полей, чем здесь, а данные [2] - это то, что мне нужно. – msmazh

+0

снова смотрит на ваш код, цикл «для gn в d [uid] .keys():» возвращается внутри первой итерации, поэтому вы никогда не будете смотреть на все клавиши Я думаю, что вам нужно сделать вместо возврата, обновите словарь (и перейдите к другим клавишам) – user2907934

Смежные вопросы