Python多线程

Python的并行开发有两种方式:fork和thread(线程)。thread比fork更轻量级,具有更好运行效率和可移植性,在需要进行并行操作的场合首推thread。

python标准库内置一个thread模块,该模块提供一个轻便简易的多线程编程接口,可以无需任何修改就能够运行在Win、Solaris、Linux等操作系统上。浏览一下thread模块:

import thread
dir(thread)

看到

['LockType', '__doc__', '__name__', '_local', 'allocate', 'allocate_lock', 'error', 'exit', 'exit_thread', 'get_ident', 'interrupt_main', 'stack_size', 'start_new', 'start_new_thread']

创建线程是我们的首要任务,我们将要用到的是start_new和start_new_thread方法,我们推荐start_new_thread,因为start_new已经是陈旧的版本。下面的代码展示了如何创建线程:

import thread
def childthread(threadid):
        print ‘I am child thread’,threadid
def parentthread():
        i=0
        while 1:
                  i+=1
                  thread.start_new_thread(childthread,(i,))
                  if raw_input()==’q':break
parentthread()

运行该程序会看到如下效果:

I am child thread 1

I am child thread 2

I am child thread 3
q

每次按下回车,屏幕上就会出现一行来自start_new_thread所创建的线程的信息,知道我们输入q按回车为止。

可见thread模块通过start_new_thread给我们提供一个基于函数的线程创建接口。start_new_thread方法有两个参数,第一个参数是我们预定义的函数(这里是childthread),也就是我们想要创建的线程体;第二个参数是一个tuple(元组),罗列线程体的函数的所有参数,为什么要用一个tuple呢?python很具灵活性,因为不管线程体有多少个参数,通过一个tuple我们就可以传递足够的参数,这里我么传递一个(i,)的tuple,表示只有一个参数。

Python中,我们可以使用N个线程同时访问该进程的内存空间,这是线程固有的特点。下面我们尝试做到这一点。

import thread
i=0
def doit(ind):
         global i
         temp=i
         i=temp+1
         print "i=%d" % i

for ind in range(1000):
         thread.start_new_thread(doit,(ind,))
raw_input()

运行代码,我们看到好奇怪的现象:

程序期待的结果是依次打印出从1到1000的值,而我们发现部分数值并没有被打印出来,而部分数值却重复打印了。原因很简单,试想现在有A、B两个线程同时访问i,执行顺序如下,假设现在i=100:
A: temp=100
B: temp=100
A: i=temp+1=100+1=101
A: 打印i=101
B: i=temp+1=100+1=101
B: 打印i=101
很显然,我们得到了两条i=101的结果,这就是为什么会出现上面的现象。原因是各个线程之间对变量的访问没有一个粒子性,就是没有实现当A线程访问变量i的时候,B线程应该等待A线程处理完后再访问i。这个就是线程同步的问题。
对于这个问题,python同样给我提供一个很轻便的接口去解决,就是锁(lock)。当一个线程申请一个锁以后,其他线程如果要申请锁,必须要等待这个锁被释放以后才能得到,从而实现线程的互相等待。下面尝试通过锁解决这个问题:
import thread

i=0

def doit(ind):
       global i
       global mutex
       mutex.acquire()
       temp=i
       i=temp+1
       print "i=%d" % i
       mutex.release()

mutex=thread.allocate_lock()
for ind in range(1000):

       thread.start_new_thread(doit,(ind,))
raw_input()

运行程序,现在我们可以看到i从1到1000很正常的打印出来了。我们把temp=i和i=temp+1语句放在申请锁和释放锁中间,就可以防止多个线程同时执行这两段代码。

Share and Enjoy:
  • Print this article!
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • LinkedIn
  • Live
  • MySpace
  • RSS
  • Slashdot
  • Technorati
  • TwitThis

Related posts:

  1. Python线程编程的两种方式
  2. Python 多线程 XML RPC的实现
  3. python range()函数的用法
  4. 序列、元组、列表、字典

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word

Contact us

Admin: Bryan Wu