Исправлено исключение strptime с блокировкой потока, но замедляющее работу программы

У меня есть следующий код, который выполняется внутри потока (полный код здесь — https://github.com/eWizardII/homobabel/blob/master/lovebird.py)

 for null in range(0,1):
            while True:
                try:
                    with open('C:/Twitter/tweets/user_0_' + str(self.id) + '.json', mode='w') as f:
                        f.write('[')
                        threadLock.acquire()
                        for i, seed in enumerate(Cursor(api.user_timeline,screen_name=self.ip).items(200)):
                            if i>0:
                                f.write(", ")
                            f.write("%s" % (json.dumps(dict(sc=seed.author.statuses_count))))
                            j = j + 1
                        threadLock.release()
                        f.write("]")
                except tweepy.TweepError, e:
                    with open('C:/Twitter/tweets/user_0_' + str(self.id) + '.json', mode='a') as f:
                        f.write("]")
                    print "ERROR on " + str(self.ip) + " Reason: ", e
                    with open('C:/Twitter/errors_0.txt', mode='a') as a_file:
                        new_ii = "ERROR on " + str(self.ip) + " Reason: " + str(e) + "\n"
                        a_file.write(new_ii)
                break

Теперь без блокировки потока я генерирую следующую ошибку:

Exception in thread Thread-117: Traceback (most recent call last):   File "C:\Python27\lib\threading.py", line 530, in __bootstrap_inner
    self.run()   File "C:/Twitter/homobabel/lovebird.py", line 62, in run
    for i, seed in enumerate(Cursor(api.user_timeline,screen_name=self.ip).items(200)): File "build\bdist.win-amd64\egg\tweepy\cursor.py", line 110, in next
    self.current_page = self.page_iterator.next()   File "build\bdist.win-amd64\egg\tweepy\cursor.py", line 85, in next
    items = self.method(page=self.current_page,
*self.args, **self.kargs)   File "build\bdist.win-amd64\egg\tweepy\binder.py", line 196, in _call
    return method.execute()   File "build\bdist.win-amd64\egg\tweepy\binder.py", line 182, in execute
    result = self.api.parser.parse(self, resp.read())   File "build\bdist.win-amd64\egg\tweepy\parsers.py", line 75, in parse
    result = model.parse_list(method.api, json)   File "build\bdist.win-amd64\egg\tweepy\models.py", line 38, in parse_list
    results.append(cls.parse(api, obj))   File "build\bdist.win-amd64\egg\tweepy\models.py", line 49, in parse
    user = User.parse(api, v)   File "build\bdist.win-amd64\egg\tweepy\models.py", line 86, in parse
    setattr(user, k, parse_datetime(v))   File "build\bdist.win-amd64\egg\tweepy\utils.py", line 17, in parse_datetime
    date = datetime(*(time.strptime(string, '%a %b %d %H:%M:%S +0000 %Y')[0:6]))   File "C:\Python27\lib\_strptime.py", line 454, in _strptime_time
    return _strptime(data_string, format)[0]   File "C:\Python27\lib\_strptime.py", line 300, in _strptime
    _TimeRE_cache = TimeRE()   File "C:\Python27\lib\_strptime.py", line 188, in __init__
    self.locale_time = LocaleTime()   File "C:\Python27\lib\_strptime.py", line 77, in __init__
    raise ValueError("locale changed during initialization") ValueError: locale changed during initialization

Проблема заключается в том, что блокировка потока включена, каждый поток запускается в основном последовательно, и для запуска каждого цикла требуется много времени, чтобы иметь какое-либо преимущество в наличии потока. Итак, если нет способа избавиться от блокировки потока, есть ли способ ускорить выполнение цикла for внутри оператора try?


person eWizardII    schedule 07.01.2011    source источник


Ответы (2)


Согласно предыдущему ответу на StackOverflow, time.strptime не является потокобезопасным . К сожалению, ошибка, указанная в этом вопросе, отличается от ошибки, с которой вы столкнулись.

Их решение состояло в том, чтобы вызывать time.strptime перед инициализацией любых потоков, а затем будут работать последующие вызовы time.strptime в различных потоках.

Я думаю, что такое же решение может сработать в вашей ситуации после изучения модулей стандартной библиотеки _strptime и locale. Я не могу быть уверен, что это сработает, так как я не могу протестировать ваш код локально, но я подумал, что могу предоставить вам потенциальное решение.

Дайте мне знать, если это работает.

Редактировать:

Я провел еще немного исследований, и стандартная библиотека Python вызывает setlocale в заголовочном файле locale.h C. Согласно документации setlocale, это не потокобезопасно, и вызовы setlocale должны происходить до инициализации потоков, как я упоминал ранее.

К сожалению, setlocale вызывается каждый раз, когда вы вызываете time.strptime. Итак, предлагаю следующее:

  1. Протестируйте решение, выложенное ранее, попробуйте вызвать time.strptime перед инициализацией потоков и снять блокировки.
  2. Если № 1 не работает, вам, вероятно, потребуется создать свою собственную функцию time.strptime, которая является потокобезопасной, как указано в документации Python для locale.
person brildum    schedule 07.01.2011
comment
Круто, большое спасибо, я попробовал первый вариант. Я рассмотрю вариант № 2 позже, так как я просто решил вернуться к скрипту oauth2 для доступа к Twitter API, поскольку у него нет этой проблемы. - person eWizardII; 08.01.2011

Проблема, с которой вы столкнулись, связана с отсутствием потокобезопасности используемых функций и модулей.

Как вы можете видеть здесь, tweepy не поддерживает повторный вход и не является потокобезопасным. Как вы можете видеть здесь, Python LocaleTime не таков.

Для многопоточного приложения, такого как ваше, оберните tweepy API через свой собственный класс, который синхронизируется (RLock'ed). Но не наследуйте от класса tweepy, создайте отношение has-a с атрибутом private для экземпляра tweepy.

person Raphael Bossek    schedule 07.01.2011
comment
Хорошо, я изучу это также, когда у меня будет больше времени, чтобы поэкспериментировать с ним, а сейчас я просто решил вернуться к oauth2, так как у него, похоже, нет этой проблемы. - person eWizardII; 08.01.2011