Python 多线程编程实现

一、多线程简单例子

#!user/bin/python
#-*- coding:utf-8 -*-
import threading
from time import ctime,sleep
def fib(x):         # 斐波那契数
    sleep(0.05)
    if x<2: return 1
    return (fib(x-2)+fib(x-1))

def fac(x):              # 阶乘
    sleep(0.3)
    if x<2 :return 1
    return x*fac(x-1)

def sum(x):               # 累加
    sleep(0.3)
    if x<2: return 1
    return (x+sum(x-1))

n = 10
nfunc1 = [fib,fac,sum]
if __name__ == '__main__':
    print "单线程程序开始时间:",ctime()
    fib(n)
    fac(n)
    sum(n)
    print"单线程程序结束时间:",ctime()
    threads = []
    print "多线程程序开始时间:", ctime()
    t = threading.Thread(target=fib,args=(n,))  # 实例化线程
    threads.append(t)
    t = threading.Thread(target=fac,args=(n,))
    threads.append(t)
    t = threading.Thread(target=sum, args=(n,))
    threads.append(t)
    nfunc = range(len(nfunc1))
    for i in  nfunc:
        threads[i].start()
    for i in nfunc:
        threads[i].join()
    print"多线程程序结束时间:", ctime()

运行结果:
这里写图片描述
从运行结果看,多线程在解决问题的效率远高于单线程。

二、基本概念

进程:是一个执行中的程序。

线程:是在同一个进程下执行的程序,并共享相同的上下文。

多线程编程:子任务相互独立,没有因果关系(各个子任务的结果并不影响其他子任务的结果)

特点:本质上是异步的;需要多个并发活动;每个活动的处理顺序是随机的;

让步:线程有一个指令指针,用于记录当前运行的上下文。当其他线程运行时,它可以被抢断(中断)或者临时挂起(也称为睡眠),这种做法叫做让步。

竞态条件(race condition):一个进程中的各个线程和主线程共享同一片数据空间。如果两个或者多个线程访问同一片数据,由于数据访问的顺序不同,可能导致结果不一致。这种情况成为竞态条件。

同步原语:大多数线程库都有一些同步原语,以允许线程管理器控制执行和访问。

主线程的作用:负责了解每个单独线程的任务、数据参数,及这些线程执行完成后会提供什么结果。主线程通过收集每个线程的结果,汇总成一个有意义的结果。

三、thread 模块
案例代码:

#!user/bin/python
#-*- coding:utf-8 -*-
import thread
from time import ctime,sleep
def loop1():
    print"start loop1 time at:",ctime()
    sleep(4)
    print"loop1 done at:",ctime()

def loop2():
    print"start loop2 time at:",ctime()
    sleep(2)
    print"loop2 done at:",ctime()

if __name__=="__main__":
    print"The program start time is:",ctime()
    thread.start_new_thread(loop1,())
   #开始一个线程,参数包括函数(对象)、函数的参数以及可选的关键字参数,即使要执行的函数没有参数,也要传递一个空的元组
    thread.start_new_thread(loop2,())
    sleep(6)
    print"The program is done at:",ctime()

thread 模块提供了基本的线程和锁定支持;thread 模块的核心函数:start_new_thread();该函数包括函数(对象),函数参数和可选的关键字参数;
注意: 即使要执行的函数不需要参数,也要传递一个空的元组。

在该应用程序中加入了sleep(6),因为如果不阻止主线程继续执行,它将直接执行 print”The program is done at:”,ctime(),然后退出,loop1() 和 loop2( ) 两个线程也将直接终止。但是,在实际的应用中,子线程往往有不同的执行时间且时间未知,单纯使用sleep 函数可能过早或者过晚的退出主程序。而锁就可以解决这类问题。

使用线程和锁的例子:

#!user/bin/python
#-*- coding:utf-8 -*-
import thread
from time import ctime,sleep
loops = [4,2]
def loop(nloop,nsec,lock):
    print"the loop",nloop," start at:",ctime()
    sleep(nsec)
    print"the loop ",nloop," done at:",ctime()
    lock.release()                                       # 释放锁
if __name__=="__main__":
    print"the Program is starting at:",ctime()
    locks = []
    nloops =range(len(loops))
    for i in nloops:
        lock = thread.allocate_lock()                    # 分配LockType 锁对象
        lock.acquire()                                   # 尝试获取锁, 相当于把锁锁上
        locks.append(lock)                               # 把锁添加到列表中
    for i in nloops:
        thread.start_new_thread(loop,(i,loops[i],locks[i]))    # 派生线程

    for i in nloops:                           # 等待:相当于暂停主线程
        while locks[i].locked():pass             # 如果获取了锁对象则返回为True, 否则返回 False
    print"the Program have done at:",ctime()

每个线程被分配一个以获得的锁。当sleep时间到了,释放对应的锁,向主线程表明该线程已完成。

thread.allocate_lock() 函数用于分配LockType 锁对象
locks.acquire() 函数用于尝试获取锁, 相当于把锁锁上
locks.locked() 每个线程执行完会释放自己的锁对象,该函数用于获取了释放的锁对象,若获取了锁对象则返回True,否则返回False。
exit() 给线程退出指令;
release() 释放锁

为什么不在上锁时启动线程:1、这里打算同步线程;2、获取锁需要一些时间,如果执行太快,可能会出现获取锁之前线程就执行结束的情况。

thread 模块缺点:

它对于进程何时退出没有控制。在主线程退出后,所有的其他线程也会被强制结束,不会发出警告或者适当的清理;

四、threading 模块

守护线程:可用于解决当主线程退出,所有子线程都将终止的问题。
threading 模块的 Thread 类是主要的执行对象,它具有thread 模块中没有的很多函数。

使用 Thread 类用于创建线程,有以下三种方法;
1、创建Thread 的实例,传递给一个函数;
2、创建Thread 的实例,传递给一个可调用的类实例;
3、派生Thread 的子类,并创建子类的实例;

创建Thread 的实例,传递给一个函数

#!user/bin/python
#-*- coding:utf-8 -*-
# 创建一个Thread 的实例,传给他一个函数
import threading
from time import ctime,sleep

loops = [2,4]
def loop(nloop,nsec):
    print"start loop",nloop," time at:",ctime()
    sleep(nsec)
    print"loop",nloop," done at:",ctime()

if __name__=="__main__":
    print"The program start time is:",ctime()
    threads = []
    nloops = range(len(loops))

    for i in nloops:
        t = threading.Thread(target=loop,args=(i,loops[i]))        # 实例化线程
        threads.append(t)
    for i in nloops:               # 开始线程
        threads[i].start()

    for i in nloops:                    #等待线程结束
        threads[i].join()              # join 方法,让主线程等待所有线程执行完毕
    print"The program is done:",ctime()

实例化Thread(调用Thread())和调用 thread.start_new_thread() 最大的区别是:前者线程不会立即开始执行;当不希望线程立即开始时,这是一个很有用的同步功能。

当所有线程分配完成后,调用每个线程的 start() 方法开始执行;join() 方法成为自旋锁,作用是将等待线程结束;
join(timeout = None),直至启动线程终止前一直挂起;除非给定了timeout(秒),否则一直处于阻塞状态。

创建Thread 的实例,传递给一个可调用的类实例
这种方法的好处是:这个类更加通用,而不局限与loop 函数,最后一个例子给出说明。

#!user/bin/python
#-*- coding:utf-8 -*-
# 创建一个Thread 的实例,传给它一个可调用的类实例
import threading
from time import ctime,sleep
loops = [4,2]

# 这个类更加通用,而不局限与loop 函数。让类保存了函数的参数、函数自身、函数名的字符串
class ThreadFunc(object):
    def __init__(self,func,args,name=""):
        self.name = name
        self.func = func
        self.args = args
    def __call__(self):     #创建新线程时,Thread 类的代码将调用T和ThreadFunc 的对象,此时会调用__call__() 这个特殊方法
        self.func(*self.args)

def loop(nloop,nsec):
    print"start loop:",nloop,"at:",ctime()
    sleep(nsec)
    print"nloop",nloop,"is done at:",ctime()

if __name__ == "__main__":
    print"The program start time is:", ctime()
    threads = []
    nloops = range(len(loops))
    for i in nloops:         # 创建 Thread 的实例
        t = threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__))
        threads.append(t)
    for i in nloops:                                 # 开始线程
        threads[i].start()

    for i in nloops:                                      # 等待线程结束
        threads[i].join()                      # join 方法,让主线程等待所有线程执行完毕
    print"The program is done:", ctime()

派生 Thread 的子类,并创建子类的实例

#!user/bin/python
#-*- coding:utf-8 -*-
# 将 Thread 子类化,而不是直接将其实例化
import threading
from time import ctime,sleep
loops = [4,2]

class MyThreadFunc(threading.Thread):
    def __init__(self,func,args,name=""):              # 调用基类构造函数
        threading.Thread.__init__(self)
        self.name = name
        self.func = func
        self.args = args
    def getResult(self):      # 该方法可用于获取返回值
        return self.res
    def run(self):
        print"The program",self.name," start time is:",ctime()
        self.res = self.func(*self.args)
        print"The program",self.name,"have done at:",ctime()

def loop(nloop,nsec):
    print"start loop:",nloop,"at:",ctime()
    sleep(nsec)
    print"nloop",nloop,"is done at:",ctime()

if __name__ == "__main__":
    print"The program start time is:", ctime()
    threads = []
    nloops = range(len(loops))

    for i in nloops:
        t = MyThreadFunc(loop,(i,loops[i]),loop.__name__)
        threads.append(t)
    for i in nloops:  # 开始线程
        threads[i].start()

    for i in nloops:  # 等待线程结束
        threads[i].join()  # join 方法,让主线程等待所有线程执行完毕
    print"The program is done:", ctime()

注意:1、MyThread 子类的构造函数必须先调用其基类的构造函数‘2、子类中必须有 run() 这个特殊方法。

使用案例:

#!user/bin/python
#-*- coding:utf-8 -*-
# 创建一个Thread 的实例,传给它一个可调用的类实例
import threading
from time import ctime,sleep

from EX4 import MyThreadFunc
from time import ctime,sleep

def fib(x):         # 斐波那契数
    sleep(0.005)
    if x<2: return 1
    return (fib(x-2)+fib(x-1))

def fac(x):              # 阶乘
    sleep(0.1)
    if x<2 :return 1
    return x*fac(x-1)

def sum(x):               # 累加
    sleep(0.1)
    if x<2: return 1
    return (x+sum(x-1))
funcs = [fib,fac,sum]
n = 12

if __name__ == '__main__':
    nfunc = range(len(funcs))
    threads = []
    print "单线程程序开始时间:",ctime()
    print"fib 计算结果为:", fib(n)
    print"fac 计算结果为:",fac(n)
    print"sum 计算结果为:",sum(n)
    print"单线程程序结束时间:",ctime()
    print "多线程程序开始时间:", ctime()
    for i in nfunc:
        t = MyThreadFunc(funcs[i],(n,),funcs[i].__name__)
        threads.append(t)
    for i in nfunc:
        threads[i].start()
    for i in nfunc:
        threads[i].join()
        print threads[i].getResult()          # 打印计算结果
    print"The program have done:"
    print"多线程程序结束时间:", ctime()

——摘自《Python 核心编程》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值