потоки не могут сократить время выполнения двух функций при одновременном запуске - PullRequest
0 голосов
/ 19 сентября 2019

У меня есть две функции f1 и f2, которые увеличивают определенное целое число раз в цикле внутри этих двух функций.

Два способа вызова этих функций.

1) Один за другим сначала f1, затем f2.2) Создайте поток t1 для запуска функции f1 и поток t2 для запуска функции f2.

Как только в приведенном ниже коде я попробовал оба способа.

from threading import Thread
import time
import datetime
from queue import Queue

def f1(a):
    for i in range(1,100000000):
        a+=1
    return a

def f2(a):
    for i in range(1,100000000):
        a+=1
    return a
if __name__ == '__main__':

    que1 = Queue()
    que2 = Queue()

    # t2 = Thread(target=f1(a),name='t2')
    a = 0
    s_t = time.time()
    print('Value of a, before calling function f1: ',a)
    a=f1(a)
    print('Value of a, after calling function f1: ',a)
    a = 0
    print('Value of a, before calling function f2: ',a)
    a=f2(a)
    print('Value of a, after calling function f2: ',a)
    print('Time taken without threads: ',datetime.timedelta(seconds=time.time()-s_t))

    s_t = time.time()
    a = 0
    print('Value of a, before calling function f1 through thread t1: ',a)

    t1 = Thread(target=lambda q, arg1: q.put(f1(arg1)), args=(que1,a),name = 't1')
    print('Value of a, before calling function f2 through thread t2: ',a)

    t2 = Thread(target=lambda q, arg1: q.put(f2(arg1)), args=(que2,a),name = 't2')

    t1.start()
    t2.start()
    t1.join()
    print('Value of a, after calling function f1 through thread t1: ',que1.get())
    t2.join()
    print('Value of a, after calling function f2 through thread t2: ',que2.get())
    print('Time taken with threads: ',datetime.timedelta(seconds=time.time()-s_t))

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

Вот вывод

Value of a, before calling function f1:  0
Value of a, after calling function f1:  99999999
Value of a, before calling function f2:  0
Value of a, after calling function f2:  99999999
Time taken without threads:  0:00:07.623239
Value of a, before calling function f1 through thread t1:  0
Value of a, before calling function f2 through thread t2:  0
Value of a, after calling function f1 through thread t1:  99999999
Value of a, after calling function f2 through thread t2:  99999999
Time taken with threads:  0:00:27.274876

Что происходит не так?

1 Ответ

1 голос
/ 19 сентября 2019

В python , только одиночный поток может работать в время из-за GIL (Global Interpreter Lock) . Что такое GIL? .Поэтому запуск потоков для интенсивной работы процессора не очень полезен в python.Но потоки отлично подходят для ввода / вывода.Надеюсь, я пояснил:)

Предполагая, что python3, вы можете использовать ProcessPoolExecutor из concurrent.futures как,

$ cat cpuintense.py
import time
from concurrent.futures import ProcessPoolExecutor


def f1(a):
    for i in range(1,100000000):
        a+=1
    return a

def f2(a):
    for i in range(1,100000000):
        a+=1
    return a

def run_in_sequence(a):
    start = time.time()
    f1(a)
    f2(a)
    end = time.time()
    print(f'[Sequential] Took {end-start} seconds')

def run_in_parallel(a):
    with ProcessPoolExecutor(max_workers=2) as pool:
        start = time.time()
        fut1 = pool.submit(f1, a)
        fut2 = pool.submit(f2, a)
        for fut in (fut1, fut2):
            print(fut.result())
        end = time.time()
        print(f'[Parallel] Took {end-start} seconds')


if __name__ == '__main__':
    a = 0
    run_in_sequence(a)
    run_in_parallel(a)

Выход:

$ python3 cpuintense.py
[Sequential] Took 6.838468790054321 seconds
99999999
99999999
[Parallel] Took 3.488879919052124 seconds

Примечание. Для окон требуется защита if __name__ == '__main__'.Из документов причина в том, что

Поскольку в Windows отсутствует os.fork (), у нее есть несколько дополнительных ограничений:

Безопасный импорт основного модуля

Make sure that the main module can be safely imported by a new Python interpreter without causing unintended side effects (such a starting a new process).

For example, under Windows running the following module would fail with a RuntimeError:

from multiprocessing import Process

def foo():
    print 'hello'

p = Process(target=foo)
p.start()

Instead one should protect the “entry point” of the program by using if __name__ == '__main__': as follows:

from multiprocessing import Process, freeze_support

def foo():
    print 'hello'

if __name__ == '__main__':
    freeze_support()
    p = Process(target=foo)
    p.start()

(The freeze_support() line can be omitted if the program will be run normally instead of frozen.)

This allows the newly spawned Python interpreter to safely import the module and then run the module’s foo() function.

Similar restrictions apply if a pool or manager is created in the main module.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...