python多线程thread,threading哪个好

thread模块提供了基本的线程和锁定支持;而threading模块提供了更高级别、功能更全面的线程管理。
应该避免使用thread模块,尽量使用threading模块,原因如下:
(1)threading模块更加先进,有更好的线程支持,并且thread模块中的一些属性会和threading模块有冲突.
(2)thread模块拥有的同步原语很少,而threading模块有很多。
(3)thread模块对于进程何时退出没有控制。当主线程结束时,所有其他线程也都强制结束,不会发出警告或者进行适当的清理。

python多线程有个全局解释器锁(global interpreter lock),这个锁的意思是任一时间只能有一个线程使用解释器,跟单cpu跑多个程序一个意思,大家都是轮着用的,这叫“并发”,不是“并行”。
多进程间共享数据,可以使用 multiprocessing.Value 和 multiprocessing.Array

在UNIX平台上,当某个进程终结之后,该进程需要被其父进程调用wait,否则进程成为僵尸进程(Zombie)。所以,有必要对每个Process对象调用join()方法 (实际上等同于wait)。对于多线程来说,由于只有一个进程,所以不存在此必要性。
多进程应该避免共享资源。在多线程中,我们可以比较容易地共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过共享内存和Manager的方法来共享资源。但这样做提高了程序的复杂度,并因为同步的需要而降低了程序的效率。

为了更好的了解多线程,首先来看个 串行执行的例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import time

def loop1():
    print 'start loop1 at ', time.ctime()
    time.sleep(4)
    print 'end loop1 at ', time.ctime()

def loop2():
    print 'start loop2 at ', time.ctime()
    time.sleep(2)
    print 'end loop2 at ', time.ctime()

def main():
    print 'start main at ', time.ctime()
    loop1()
    loop2()
    print 'end main at ', time.ctime()


if __name__ == '__main__':
    main()

这个串行执行的例子,先执行loop1 ,再执行loop2 。

由于使用thread模块时,主线程结束时,所有其他线程也都强制结束。下面例子采取让主线程sleep的方式来保证子线程先完成。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import thread
import time

def loop1():
    print 'start loop1 at ', time.ctime()
    time.sleep(4)
    print 'end loop1 at ', time.ctime()

def loop2():
    print 'start loop2 at ', time.ctime()
    time.sleep(2)
    print 'end loop2 at ', time.ctime()

def main_thread():
    print 'start main at ', time.ctime()
    thread.start_new_thread(loop1, ())
    thread.start_new_thread(loop2, ())
    time.sleep(6)
    print 'All done at ', time.ctime()


if __name__ == '__main__':
    main_thread()

由于loop1和loop2函数过于简单,我们可以预估loop1和loop2的完成时间,然后在main_thread函数直接相加两个时间,同时,在4s时,loop1和loop2都已经执行完了,没有实现多线程的优势。在实际情况中,这种方法是十分不可取的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import time
import thread

loops = [44, 42]

def loop(nsecs, loopname, lock):
    print 'start ', loopname, ' at: ', time.ctime()
    time.sleep(nsecs)
    print 'end ', loopname, ' at: ', time.ctime()
    lock.release()

def main():
    print 'start main at ', time.ctime()
    # locks保存锁对象的列表
    locks = []
    nloops = range(len(loops))

    for i in nloops:
        lock = thread.allocate()
        lock.acquire()
        locks.append(lock)

    for i in nloops:
        thread.start_new_thread(loop, (loops[i], ('loop' + str(i)), locks[i]))

    for i in nloops:
        while locks[i].locked():
            pass

    print 'All done at: ', time.ctime()


if __name__ == '__main__':
    main()

每个线程将被分配一个已获得的锁。当sleep()的时间到了的时候,释放对应的锁,向主线程表明该线程已完成。
通过使用thread.allocate_lock()函数得到锁对象,然后通过acquire()方法取得(每个锁)。取得锁效果相当于“把锁锁上”。
最后一个循环只是坐在那里等待(暂停主线程),直到所有锁都被释放之后才会继续执行。

上边提到,应该使用更高级的threading模块实现多线程,这里研究使用Thread类来实现多线程,threading模块支持守护线程。使用Thread类,有多种创建线程的方法:
(1)创建Thread 的实例,传给它一个函数。
(2)创建Thread 的实例,传给它一个可调用的类实例。
(3)派生Thread 的子类,并创建子类的实例。
Thread类的常用方法:

方法说明
init(group=None, tatget=None, name=None, args=(),kwargs ={}, verbose=None, daemon=None)实例化一个线程对象,需要有一个可调用的target,以及其参数args或kwargs。还可以传递name 或group 参数,不过后者还未实现。此外, verbose 标志也是可接受的。而daemon 的值将会设定thread.daemon 属性/标志
start()开始执行该线程
run()定义线程功能的方法(通常在子类中被应用开发者重写)
join(timeout=None)直至启动的线程终止之前一直挂起;除非给出了timeout(秒),否则会一直阻塞

在第3节的多线程例子中,需要自己管理锁来实现多线程,这样其实比较麻烦。使用threading.Thread类时,就省去了锁的管理,实例化Thread(调用Thread())和调用thread.start_new_thread()的最大区别是新线程不会立即开始执行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from time import ctime
from time import sleep
import threading

sleepsecs = [4, 8]

def loop(loopname, secs):
    print 'start loop',loopname, ' at: ', ctime()
    sleep(secs)
    print 'end loop',loopname, ' at: ', ctime()


if __name__ == '__main__':
    # Thread对象列表
    threads = []

    for i in range(len(sleepsecs)):
        thread = threading.Thread(target=loop, args=(i, sleepsecs[i]))
        threads.append(thread)

    print 'start main at :', ctime()
    # 逐个启动线程
    for i in range(len(sleepsecs)):
        threads[i].start()
        sleep(0.001)

    for i in range(len(sleepsecs)):
        threads[i].join()

    print 'end main at ', ctime()

下面添加一个ThreadFunc类,在实例化Thread类时,实际做了2次实例化,包括Thread和ThreadFunc。
当创建新线程时,Thread 类的代码将调用ThreadFunc 对象,此时会调用call()这个特殊方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from time import sleep
from time import ctime
from threading import Thread

class ThreadFunc(object):
    # func: 多线程要执行的函数  该参数就是一个函数对象
    # loopname: 执行函数名称
    # secs: sleep等待时间
    def __init__(self, func, loopname, secs):
        self.func = func
        self.loopname = loopname
        self.secs = secs

    def __call__(self):
        self.func(self.loopname, self.secs)

def loop(loopname, secs):
    print 'start loop ', loopname, ' at: ', ctime()
    sleep(secs)
    print 'end loop ', loopname, ' at: ', ctime()


if __name__ == '__main__':
    threads = []
    secs = [4, 8]

    print 'start main at: ', ctime()
    for i in range(len(secs)):
        thread = Thread(target=ThreadFunc(loop, i, secs[i]))
        threads.append(thread)

    for i in range(len(secs)):
        threads[i].start()
        sleep(0.001)

    for i in range(len(secs)):
        threads[i].join()

    print 'end main at:', ctime()

派生子类时,只需要创建子类的实例即可,不用再创建Thread类实例。需要注意下边2点:
1.MyThread子类的构造函数必须先调用其基类的构造函数。
2.必须在子类中定义run()方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from threading import Thread
from time import ctime
from time import sleep

class MyThread(Thread):
    # func:该参数是多线程执行的函数
    # args:func函数的参数列表,多个参数的列表
    # name:名称
    def __init__(self, func, args, name):
        # MyThread子类的构造函数必须先调用其基类的构造函数
        Thread.__init__(self)
        self.func = func
        self.args = args
        self.name = name

    # 必须在子类中定义run()方法
    def run(self):
        self.func(*self.args)

def loop(nloop, secs):
    print 'start loop ', nloop, ' at: ', ctime()
    sleep(secs)
    print 'end loop ', nloop, ' at: ', ctime()


if __name__ == '__main__':
    seconds = [4, 8]
    threads = []
    print 'start main at: ', ctime()

    # 创建线程,但是未启动
    for i in range(len(seconds)):
        thread = MyThread(loop, (i, seconds[i]), '')
        threads.append(thread)

    # 启动线程
    for i in range(len(seconds)):
        threads[i].start()
        sleep(0.001)

    for i in range(len(seconds)):
        threads[i].join()

    print 'end main at: ', ctime()

为了应用更加方便,将MyThread类独立抽象出来,后边直接引入就可以使用,并且保存下返回结果,做得更加通用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from threading import Thread
from time import ctime

class MyThread(Thread):
    def __init__(self, func, args, name):
        Thread.__init__(self)
        self.func = func
        self.args = args
        self.name = name

    def getResult(self):
        return self.res

    def run(self):
        print 'starting ', self.name, ' at: ', ctime()
        self.func(*self.args)
        print 'finish ', self.name , ' at: ', ctime()

为了展示多线程的实现结果,在每次计算的时候,sleep 0.1秒,并试图用多线程优化。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from time import sleep
from time import ctime
from MyThread import MyThread


# 递归斐波那契
def recursion_fib(x):
    sleep(0.1)
    if x < 3:
        return 1
    else:
        return recursion_fib(x-2) + recursion_fib(x-1)

# 递归阶乘
def recursion_multiply(x):
    sleep(0.1)
    if x < 2:
        return 1
    else:
        return x*recursion_multiply(x-1)

# 递归实现时,只需要考虑这个函数在不同条件下的返回值,需要有终止条件
def recursion_sum(x):
    sleep(0.1)
    if x < 2:
        return 1
    else:
        return x+recursion_sum(x-1)


if __name__ == '__main__':
    func_names = ['fib', 'recMul', 'recSum']
    funcs = [recursion_fib, recursion_multiply, recursion_sum]
    threads = []

    print 'start Single Thread -------------------'
    for i in range(len(funcs)):
        print 'start function ', func_names[i], ' at: ', ctime()
        funcs[i](10)
        print 'end function ', func_names[i], ' at: ', ctime()
    print 'end Single Thread -------------------'

    print 'start Multiple Thread -------------------'
    for i in range(len(funcs)):
        thread = MyThread(funcs[i], (10,), func_names[i])
        threads.append(thread)

    for i in range(len(funcs)):
        threads[i].start()
        sleep(0.001)

    for i in range(len(funcs)):
        threads[i].join()
        print threads[i].getResult()

    print 'end Multiple Thread -------------------'

随机文章