2013-08-07 2 views
1

У меня есть видео 450mb. Я хотел бы, чтобы загрузить его на xvideos.com я использую в моем сценарииЗагрузить большой файл слишком медленно

xvideos_log_data = {'login': xv_login, 
        'password': password, 
        'referer': 'http://upload.xvideos.com/account', 
        'log': 'Login to your account'} 

def xvideos(f_path): 
    _print('xvideos started uploading...') 

    try: 
     s = requests.Session() 
     s.post('http://upload.xvideos.com/account', data=xvideos_log_data, headers=headers) 
     rp = s.get('http://upload.xvideos.com/account/uploads/new') 
     apc = re.search(r'onclick="launch_upload_basic\(\'(.*?)\'\)', rp.text).group(1) 

     payload = {'APC_UPLOAD_PROGRESS': apc, 
        'message': ''} 
     r = s.post('http://upload.xvideos.com/account/uploads/submit?video_type=other', 
        data=payload, 
        files={'upload_file': open(f_path, 'rb')}, headers=headers) 
     edt = re.search(r'<a href="(.*?)" target="_top"', r.text) 
     if edt is None: 
      _print(re.search(r'inlineError.*>(.*?)<', r.text).group(1)) 
      return 
     payload = {'title': make_title(), 
        'keywords': ' '.join(make_tags()), 
        'description': choice(description), 
        'hide': 0, 
        'update_video_information': 'Update information'} 
     r = s.post('http://upload.xvideos.com' + edt.group(1), data=payload, headers=headers) 

     _print('xvideos finished uploading') 

    except Exception as error: 
     _print(error) 

    finally: 
     return 

Проблема заключается в том, что загрузка происходит очень медленно, но успешно. Я запускаю скрипт на своем сервере. Когда я пытаюсь загрузить в браузере - это быстро.

В чем проблема?

ответ

4

Проблема, вероятно, в коде Python httplib под библиотекой запросов.

Это было ужасно для потокового кодирования в старых версиях Python (2.2), теперь это довольно плохо. Заменив его с помощью специально созданного слоя http непосредственно на сокете и обработчиков буферов, я мог бы получить приложение для потоковой передачи с 2% -м процессором и как использование полной ссылки на быстрой сетевой ссылке. Из-за очень неэффективной буферизации Httplib мог достичь только 1 Мбайт/с при 50% или более использования ЦП. httplib отлично подходит для коротких запросов, но не настолько хорош для огромных загрузок (без настройки/взлома).

Вы можете попробовать несколько вещей, чтобы сделать вещи лучше, в зависимости от сети и настройки ОС:

  1. Настройте свои гнезда буферы через setsockoptionSO_SNDBUF, если вам не нужно много соединений и иметь быстрый сети, возможно что-то вроде 4 МБ или более, чтобы уменьшить проблемы с всегда пустыми буферами на быстрых трубах (10GE и более)

  2. Используйте другую http-библиотеку (например, pycurl или Twisted с некоторыми исправлениями) и используйте более крупные буферы для переводов, например сделайте каждый вызов socket.send() переместите несколько МБ данных, а не некоторые крошечные буферы 4 КБ.

Python может почти полностью использовать 10 GE link, если все сделано правильно.

+0

На самом деле, вы, вероятно, может получить вещи быстрее для USECASE, если у вас есть 64-битный питона и достаточно памяти, просто загрузки/mmaping весь файл сразу и передать его в качестве данных вместо ПОСРЕДСТВОМ файлов. (так как вы можете избежать медленной кодировки с этим). – schlenk

+0

У меня 1 ГБ ОЗУ на сервере ubuntu 12.10 x64. Я попробую эти идеи. Благодарю. – Alex

2

У меня была такая же проблема при загрузке на Amazon S3.

Мой браузер может загружать файлы со скоростью 8 Мбайт/с, но httplib или запросы только со скоростью 1 МБ/с.

После большого поиска я обнаружил, что httplib действительно был ответственным.

Размер блока был зафиксирован в 8192.

Я создал этот обезьяна патч и испытал много значений 20MB к 500MB файлов.

С 400000, я получаю ту же скорость, что и мой браузер: 8 МБ/с. :)

import httplib 
import httplib2 

def patch_httplib(bsize=400000): 
    """ Update httplib block size for faster upload (Default if bsize=None) """ 
    if bsize is None: 
     bsize = 8192 
    def send(self, data, sblocks=bsize): 
     """Send `data' to the server.""" 
     if self.sock is None: 
      if self.auto_open: 
       self.connect() 
      else: 
       raise httplib.NotConnected() 
     if self.debuglevel > 0: 
      print "send:", repr(data) 
     if hasattr(data, 'read') and not isinstance(data, list): 
      if self.debuglevel > 0: print "sendIng a read()able" 
      datablock = data.read(sblocks) 
      while datablock: 
       self.sock.sendall(datablock) 
       datablock = data.read(sblocks) 
     else: 
      self.sock.sendall(data) 
    httplib2.httplib.HTTPConnection.send = send 
Смежные вопросы