博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
3. 线程和进程
阅读量:6573 次
发布时间:2019-06-24

本文共 10089 字,大约阅读时间需要 33 分钟。

Python Standard Library

翻译: Python 江湖群

2008-03-28 13:11:52

 

目录

 


 

[index.html 返回首页]

 


 

 

1. 线程和进程

  • "Well, since you last asked us to stop, this thread has moved from discussing languages suitable for professional programmers via accidental users to computer-phobic users. A few more iterations can make this thread really interesting..." - eff-bot, June 1996

 


 

 

1.1. 概览

本章将介绍标准 Python 解释器中所提供的线程支持模块. 注意线程支持模块是可选的, 有可能在一些 Python 解释器中不可用.

本章还涵盖了一些 Unix 和 Windows 下用于执行外部进程的模块.

 

1.1.1. 线程

执行 Python 程序的时候, 是按照从主模块顶端向下执行的. 循环用于重复执行部分代码, 函数和方法会将控制临时移交到程序的另一部分.

通过线程, 你的程序可以在同时处理多个任务. 每个线程都有它自己的控制流. 所以你可以在一个线程里从文件读取数据, 另个向屏幕输出内容.

为了保证两个线程可以同时访问相同的内部数据, Python 使用了 global interpreter lock (全局解释器锁). 在同一时间只可能有一个线程执行 Python 代码; Python 实际上是自动地在一段很短的时间后切换到下个线程执行, 或者等待 一个线程执行一项需要时间的操作(例如等待通过 socket 传输的数据, 或是从文件中读取数据).

全局锁事实上并不能避免你程序中的问题. 多个线程尝试访问相同的数据会导致异常 状态. 例如以下的代码:

 

def getitem(key):    item = cache.get(key)    if item is None:        # not in cache; create a new one        item = create_new_item(key)        cache[key] = item    return item

如果不同的线程先后使用相同的 key 调用这里的 getitem 方法, 那么它们很可能会导致相同的参数调用两次 create_new_item . 大多时候这样做没有问题, 但在某些时候会导致严重错误.

不过你可以使用 lock objects 来同步线程. 一个线程只能拥有一个 lock object , 这样就可以确保某个时刻 只有一个线程执行 getitem 函数.

 

1.1.2. 进程

在大多现代操作系统中, 每个程序在它自身的进程( process )内执行. 我们通过在 shell 中键入命令或直接在菜单中选择来执行一个程序/进程. Python 允许你在一个脚本内执行一个新的程序.

大多进程相关函数通过 os 模块定义. 相关内容请参阅  .

 


 

 

1.2. threading 模块

(可选) threading 模块为线程提供了一个高级接口, 如  所示. 它源自 Java 的线程实现. 和低级的 thread 模块相同, 只有你在编译解释器时打开了线程支持才可以使用它 .

你只需要继承 Thread 类, 定义好 run 方法, 就可以创建一 个新的线程. 使用时首先创建该类的一个或多个实例, 然后调用 start 方法. 这样每个实例的 run 方法都会运行在它自己的线程里.

 

1.2.0.1. Example 3-1. 使用 threading 模块

 

File: threading-example-1.pyimport threadingimport time, randomclass Counter:    def _ _init_ _(self):        self.lock = threading.Lock()        self.value = 0    def increment(self):        self.lock.acquire() # critical section        self.value = value = self.value + 1        self.lock.release()        return valuecounter = Counter()class Worker(threading.Thread):    def run(self):        for i in range(10):            # pretend we're doing something that takes 10�00 ms            value = counter.increment() # increment global counter            time.sleep(random.randint(10, 100) / 1000.0)            print self.getName(), "-- task", i, "finished", value## try itfor i in range(10):    Worker().start() # start a worker*B*Thread-1 -- task 0 finished 1Thread-3 -- task 0 finished 3Thread-7 -- task 0 finished 8Thread-1 -- task 1 finished 7Thread-4 -- task 0 Thread-5 -- task 0 finished 4finished 5Thread-8 -- task 0 Thread-6 -- task 0 finished 9finished 6...Thread-6 -- task 9 finished 98Thread-4 -- task 9 finished 99Thread-9 -- task 9 finished 100*b*

 使用了 Lock 对象来在全局 Counter 对象里创建临界区 (critical section). 如果删除了 acquire 和 release 语句, 那么 Counter 很可能不会到达 100.

 


 

 

1.3. Queue 模块

Queue 模块提供了一个线程安全的队列 (queue) 实现, 如  所示. 你可以通过它在多个线程里安全访问同个对象.

 

1.3.0.1. Example 3-2. 使用 Queue 模块

 

File: queue-example-1.pyimport threadingimport Queueimport time, randomWORKERS = 2class Worker(threading.Thread):    def _ _init_ _(self, queue):        self._ _queue = queue        threading.Thread._ _init_ _(self)    def run(self):        while 1:            item = self._ _queue.get()            if item is None:                break # reached end of queue            # pretend we're doing something that takes 10�00 ms            time.sleep(random.randint(10, 100) / 1000.0)            print "task", item, "finished"## try itqueue = Queue.Queue(0)for i in range(WORKERS):    Worker(queue).start() # start a workerfor i in range(10):    queue.put(i)for i in range(WORKERS):    queue.put(None) # add end-of-queue markers*B*task 1 finishedtask 0 finishedtask 3 finishedtask 2 finishedtask 4 finishedtask 5 finishedtask 7 finishedtask 6 finishedtask 9 finishedtask 8 finished*b*

 展示了如何限制队列的大小. 如果队列满了, 那么控制主线程 (producer threads) 被阻塞, 等待项目被弹出 (pop off).

 

1.3.0.2. Example 3-3. 使用限制大小的 Queue 模块

 

File: queue-example-2.pyimport threadingimport Queueimport time, randomWORKERS = 2class Worker(threading.Thread):    def _ _init_ _(self, queue):        self._ _queue = queue        threading.Thread._ _init_ _(self)    def run(self):        while 1:            item = self._ _queue.get()            if item is None:                break # reached end of queue            # pretend we're doing something that takes 10�00 ms            time.sleep(random.randint(10, 100) / 1000.0)            print "task", item, "finished"## run with limited queuequeue = Queue.Queue(3)for i in range(WORKERS):    Worker(queue).start() # start a workerfor item in range(10):    print "push", item    queue.put(item)for i in range(WORKERS):    queue.put(None) # add end-of-queue markers*B*push 0push 1push 2push 3push 4push 5task 0 finishedpush 6task 1 finishedpush 7task 2 finishedpush 8task 3 finishedpush 9task 4 finishedtask 6 finishedtask 5 finishedtask 7 finishedtask 9 finishedtask 8 finished*b*

你可以通过继承 Queue 类来修改它的行为.  为我们展示了一个简单的具有优先级的队列. 它接受一个元组作为参数, 元组的第一个成员表示优先级(数值越小优先级越高).

 

1.3.0.3. Example 3-4. 使用 Queue 模块实现优先级队列

 

File: queue-example-3.pyimport Queueimport bisectEmpty = Queue.Emptyclass PriorityQueue(Queue.Queue):    "Thread-safe priority queue"    def _put(self, item):        # insert in order        bisect.insort(self.queue, item)## try itqueue = PriorityQueue(0)# add items out of orderqueue.put((20, "second"))queue.put((10, "first"))queue.put((30, "third"))# print queue contentstry:    while 1:        print queue.get_nowait()except Empty:    pass*B*thirdsecondfirst*b*

 展示了一个简单的堆栈 (stack) 实现 (末尾添加, 头部弹出, 而非头部添加, 头部弹出).

 

1.3.0.4. Example 3-5. 使用 Queue 模块实现一个堆栈

 

File: queue-example-4.pyimport QueueEmpty = Queue.Emptyclass Stack(Queue.Queue):    "Thread-safe stack"        def _put(self, item):        # insert at the beginning of queue, not at the end        self.queue.insert(0, item)    # method aliases    push = Queue.Queue.put    pop = Queue.Queue.get    pop_nowait = Queue.Queue.get_nowait## try itstack = Stack(0)# push items on stackstack.push("first")stack.push("second")stack.push("third")# print stack contentstry:    while 1:        print stack.pop_nowait()except Empty:    pass*B*thirdsecondfirst*b*

 


 

 

1.4. thread 模块

(可选) thread 模块提为线程提供了一个低级 (low_level) 的接口, 如  所示. 只有你在编译解释器时打开了线程支持才可以使用它. 如果没有特殊需要, 最好使用高级接口 threading 模块替代.

 

1.4.0.1. Example 3-6. 使用 thread 模块

 

File: thread-example-1.pyimport threadimport time, randomdef worker():    for i in range(50):        # pretend we're doing something that takes 10�00 ms        time.sleep(random.randint(10, 100) / 1000.0)        print thread.get_ident(), "-- task", i, "finished"## try it out!for i in range(2):    thread.start_new_thread(worker, ())time.sleep(1)print "goodbye!"*B*311 -- task 0 finished265 -- task 0 finished265 -- task 1 finished311 -- task 1 finished...265 -- task 17 finished311 -- task 13 finished265 -- task 18 finishedgoodbye!*b*

注意当主程序退出的时候, 所有的线程也随着退出. 而 threading 模块不存在这个问题 . (该行为可改变)

 


 

 

1.5. commands 模块

(只用于 Unix) commands 模块包含一些用于执行外部命令的函数.  展示了这个模块.

 

1.5.0.1. Example 3-7. 使用 commands 模块

 

File: commands-example-1.pyimport commandsstat, output = commands.getstatusoutput("ls -lR")print "status", "=>", statprint "output", "=>", len(output), "bytes"*B*status => 0output => 171046 bytes*b*

 


 

 

1.6. pipes 模块

(只用于 Unix) pipes 模块提供了 "转换管道 (conversion pipelines)" 的支持. 你可以创建包含许多外部工具调用的管道来处理多个文件. 如  所示.

 

1.6.0.1. Example 3-8. 使用 pipes 模块

 

File: pipes-example-1.pyimport pipest = pipes.Template()# create a pipeline# 这里 " - " 代表从标准输入读入内容t.append("sort", "--")t.append("uniq", "--")# filter some text# 这里空字符串代表标准输出t.copy("samples/sample.txt", "")*B*Alan Jones (sensible party)Kevin Phillips-Bong (slightly silly)Tarquin Fin-tim-lin-bin-whin-bim-lin-bus-stop-F'tang-F'tang-Olé-Biscuitbarrel*b*

 


 

 

1.7. popen2 模块

popen2 模块允许你执行外部命令, 并通过流来分别访问它的 stdin 和 stdout ( 可能还有 stderr ).

在 python 1.5.2 以及之前版本, 该模块只存在于 Unix 平台上. 2.0 后, Windows 下也实现了该函数.  展示了如何使用该模块来给字符串排序.

 

1.7.0.1. Example 3-9. 使用 popen2 模块对字符串排序Module to Sort Strings

 

File: popen2-example-1.pyimport popen2, stringfin, fout = popen2.popen2("sort")fout.write("foo\n")fout.write("bar\n")fout.close()print fin.readline(),print fin.readline(),fin.close()*B*barfoo*b*

 展示了如何使用该模块控制应用程序 .

 

1.7.0.2. Example 3-10. 使用 popen2 模块控制 gnuchess

 

File: popen2-example-2.pyimport popen2import stringclass Chess:    "Interface class for chesstool-compatible programs"    def _ _init_ _(self, engine = "gnuchessc"):        self.fin, self.fout = popen2.popen2(engine)        s = self.fin.readline()        if s != "Chess\n":            raise IOError, "incompatible chess program"    def move(self, move):        self.fout.write(move + "\n")        self.fout.flush()        my = self.fin.readline()        if my == "Illegal move":            raise ValueError, "illegal move"        his = self.fin.readline()        return string.split(his)[2]    def quit(self):        self.fout.write("quit\n")        self.fout.flush()## play a few movesg = Chess()print g.move("a2a4")print g.move("b2b3")g.quit()*B*b8c6e7e5*b*

 


 

 

1.8. signal 模块

你可以使用 signal 模块配置你自己的信号处理器 (signal handler), 如  所示. 当解释器收到某个信号时, 信号处理器会立即执行.

 

1.8.0.1. Example 3-11. 使用 signal 模块

 

File: signal-example-1.pyimport signalimport timedef handler(signo, frame):    print "got signal", signosignal.signal(signal.SIGALRM, handler)# wake me up in two secondssignal.alarm(2)now = time.time()time.sleep(200)print "slept for", time.time() - now, "seconds"*B*got signal 14slept for 1.99262607098 seconds*b*

 


 

 

 

PythonStandardLib/chpt3 (2009-12-25 07:15:19由localhost编辑)

 
  • Page.execute = 0.178s  
  • getACL = 0.112s  
  • init = 0.002s  
  • load_multi_cfg = 0.000s  
  • run = 0.667s  
  • send_page = 0.634s  
  • send_page_content = 0.185s  
  • send_page_content|1 = 0.059s  
  • send_page|1 = 0.085s  
  • total = 0.669s

转载于:https://www.cnblogs.com/soft115/archive/2011/11/29/2267605.html

你可能感兴趣的文章
Struts2简单入门实例
查看>>
基于layui的select区域联动
查看>>
Android应用及应用管理
查看>>
2012CSDN年度博客之星评选http://vote.blog.csdn.net/item/blogstar/xyz_lmn
查看>>
ETL 工具的比较:Talend,Kettle,Informatica 等
查看>>
安装 mysql 数据库, 并做 主 从(二)
查看>>
Jquery操作css
查看>>
Udp、Tcp、Http Socket
查看>>
Linux系统与网络服务管理技术大全(第2版)
查看>>
JAVA获取同一路径下所有子类或接口实现类
查看>>
在XCode中使用SVN
查看>>
再让大家清爽一下,给加班的oscer们,哈
查看>>
shell基础(下) 特殊符号
查看>>
合格前端系列第九弹-前端面试那些事
查看>>
js substring和substr的区别实例,一目了然
查看>>
ANT自动化压缩合并JS/CSS和更改版本号
查看>>
如果做职业生涯规划
查看>>
【工具使用系列】一小时学会使用MATLAB OPC 工具箱(OPC Toolbox)
查看>>
node.js学习笔记之模拟路由
查看>>
java高级_02
查看>>