线程同时运行时无法减少两个函数的运行时间 [英] threads not able to reduce the run time of two function when run at once

查看:70
本文介绍了线程同时运行时无法减少两个函数的运行时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个函数 f1f2,它们在这两个函数内的循环中递增整数特定次数.

I have two functions f1 and f2 which increment an integer specific number of times in a loop inside these two functions.

我调用这些函数的两种方式.

Two ways I call these functions.

1) 一个接一个,即先f1 然后f2.2) 创建一个线程t1来运行函数f1和线程t2来运行函数f2.

1) One by one, that is first f1 then f2. 2) Create a thread t1 to run function f1 and thread t2 to run function f2.

在下面的代码中,我已经尝试了两种方法.

As soon in the code below, I have tried both the ways.

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))

期望线程比一个接一个调用函数更快地完成工作,但这里并非如此.

Expected threads to do the jobs faster than calling the functions one after the other but it's not the case here.

这是输出

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

出了什么问题?

推荐答案

python中,一次只能运行一个单线程,因为GIL(全局解释器锁).什么是 GIL?.所以在python中为cpu密集型操作运行线程并不是很有用.但是线程非常适合 I/O.我希望,我澄清了:)

In python, only a single thread can run at a time, because of the GIL(Global Interpreter Lock). What is a GIL?. So running threads for cpu intensive operation is not very useful in python. But threads are great for I/O. I hope, i clarified :)

假设 python3,你可以从 concurrent.futures 使用 ProcessPoolExecutor 像,

Assuming python3, you could use ProcessPoolExecutor from concurrent.futures like,

$ 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

注意:Windows 需要 if __name__ == '__main__' 保护.来自 docs 的原因是,

Note: The if __name__ == '__main__' guard is required for windows. From the docs the reason is,

由于 Windows 缺少 os.fork() 它有一些额外的限制:

Since Windows lacks os.fork() it has a few extra restrictions:

安全导入主模块

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.

这篇关于线程同时运行时无法减少两个函数的运行时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆