Есть ли способ запустить cpython на неустойчивой нити, не рискуя столкнуться?

У меня есть программа, которая запускает множество запросов urllib в INFINITE LOOP, что делает мою программу очень медленной, поэтому я попытался поместить их в виде потоков. Urllib использует cpython глубоко в модуле сокета, поэтому создаваемые потоки просто складываются и ничего не делают, потому что python GIL предотвращает одновременное выполнение двух команд cpython в неустойчивых потоках. Я запускаю Windows XP с Python 2.5, поэтому я не могу использовать многопроцессорный модуль. Я попробовал посмотреть модуль подпроцесса, чтобы посмотреть, есть ли способ выполнить код python в подпроцессе, но ничего. Если у кого-то есть способ, чтобы я мог создать подпроцесс python через функцию, как в многопроцессе, это было бы здорово.

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

EDIT: Вот пример кода в моей текущей программе.

    url = "http://example.com/upload_image.php?username=Test&password=test"
    url = urllib.urlopen(url, data=urllib.urlencode({"Image": raw_image_data})).read()
    if url.strip().replace("\n", "") != "":
        print url

Я сделал тест, и оказалось, что urllib2 urlopen с объектом Request и без него все еще медленнее или медленнее. Я создал собственный пользовательский модуль времени, подобный модулю, и выше занимает около 0,5-2 секунд, что ужасно для моей программы.

Ответы

Ответ 1

Urllib использует cpython глубоко в модуле сокета, поэтому потоки которые создаются, просто складываются и ничего не делают, потому что python GIL предотвращает выполнение двух команд cpython в неуверенном потоков в то же время.

Неправильно. Хотя это распространенное заблуждение. CPython может и выпускает GIL для операций ввода-вывода (посмотрите на Py_BEGIN_ALLOW_THREADS в socketmodule.c). Хотя один поток ожидает завершения ввода-вывода, другие потоки могут выполнять некоторую работу. Если вызовы urllib являются узким местом в вашем script, тогда потоки могут быть одним из приемлемых решений.

Я запускаю Windows XP с Python 2.5, поэтому я не могу использовать многопроцессорный модуль.

Вы можете установить Python 2.6 или новее или использовать Python 2.5; вы можете установить multiprocessing отдельно.

Я создал собственный пользовательский модуль времени, подобный модулю, и выше занимает около 0,5-2 секунд, что ужасно для моей программы.

Производительность urllib2.urlopen('http://example.com...).read() в основном зависит от внешних факторов, таких как DNS, латентность/пропускная способность сети, производительность самого сервера example.com.

Здесь приведен пример script, который использует как threading, так и urllib2:

import urllib2
from Queue import Queue
from threading import Thread

def check(queue):
    """Check /n url."""
    opener = urllib2.build_opener() # if you use install_opener in other threads
    for n in iter(queue.get, None):
        try:
            data = opener.open('http://localhost:8888/%d' % (n,)).read()
        except IOError, e:
            print("error /%d reason %s" % (n, e))
        else:
            "check data here"

def main():
    nurls, nthreads = 10000, 10

    # spawn threads
    queue = Queue()
    threads = [Thread(target=check, args=(queue,)) for _ in xrange(nthreads)]
    for t in threads:
        t.daemon = True # die if program exits
        t.start()

    # provide some work
    for n in xrange(nurls): queue.put_nowait(n)
    # signal the end
    for _ in threads: queue.put(None)
    # wait for completion
    for t in threads: t.join()

if __name__=="__main__":
   main()

Чтобы преобразовать его в многопроцессорную систему script, просто используйте разные импорты, и ваша программа будет использовать несколько процессов:

from multiprocessing import Queue
from multiprocessing import Process as Thread

# the rest of the script is the same

Ответ 2

Если вы хотите многопоточность, Jython может быть вариантом, так как он не имеет GIL.

Я согласен с @Jan-Philip и @Piotr. Для чего вы используете urllib?