做者博客:http://zzir.cnpython
进程是执行中的计算机程序。每一个进程都拥有本身的地址空间、内存、数据栈及其它的辅助数据。操做系统管理着全部的进程,并为这些进程合理分配时间。进程能够经过派生新的进程来执行其它任务,不过每一个进程都拥有本身的内存和数据栈等,进程之间的数据交换采用 进程间通讯(IPC) 方式。多线程
线程在进程之下执行,一个进程下能够运行多个线程,它们之间共享相同上下文。线程包括开始、执行顺序和结束三部分。它有一个指针,用于记录当前运行的上下文。当其它线程执行时,它能够被抢占(中断)和临时挂起(也称睡眠) ——这种作法叫作 让步(yielding)。并发
一个进程中的各个线程与主进程共享同一片数据空间,与独立进程相比,线程之间信息共享和通讯更加容易。线程通常以并发执行,正是因为这种并发和数据共享机制,使多任务间的协做成为可能。固然,这种共享也并非没有风险的,若是多个线程访问同一数据空间,因为访问顺序不一样,可能致使结果不一致,这种状况一般称为竞态条件(race condition),不过大多数线程库都有同步原语,以容许线程管理器的控制执行和访问;另外一个要注意的问题是,线程没法给予公平执行时间,CPU 时间分配会倾向那些阻塞更少的函数。app
Python 代码执行由 Python 虚拟机 (又名解释器主循环) 进行控制。Python 在设计时是这样考虑的,在主循环中同时只能有一个控制线程在执行。对 Python 虚拟机的访问由 全局解释器(GIL) 控制,这个锁用于,当有多个线程时保证同一时刻只能有一个线程在运行。dom
因为 Python 的 GIL 的限制,多线程更适合 I/O 密集型应用( I/O 释放了 GIL,能够容许更多的并发),对于计算密集型应用,为了实现更好的并行性,适合使用多进程,已便利用 CPU 的多核优点。Python 的多进程相关模块:subprocess、multiprocessing、concurrent.futureside
threading 是 Python 高级别的多线程模块。函数
Lock.acquire()
, RLock.acquire()
, Condition.wait()
容许的最大值threading 可用对象列表:ui
Thread 对象的属性有:Thread.name
、Thread.ident
、Thread.daemon
。详见(The Python Standard Library)操作系统
Thread 对象方法:
Thread.start()
、Thread.run()
、Thread.join(timeout=None)
、Thread.getName
、Thread.setName
、Thread.is_alive()
、Thread.isDaemon()
、Thread.setDaemon()
。详见(The Python Standard Library)线程
使用 Thread 类,能够有不少种方法来建立线程,这里使用常见的两种:
#!/usr/bin/env python3 import threading from random import randint from time import sleep, ctime def hi(n): sleep(n) print("ZzZzzz, sleep: ", n) # 打印 Sleep 的秒数 def main(): print("### Start at: ", ctime()) for i in range(10): hi(randint(1,2)) # 调用十次,每次 Sleep 1秒或2秒 print("### Done at: ", ctime()) if __name__ == '__main__': main()
运行结果:
### Start at: Thu Sep 1 14:11:00 2016 ZzZzzz, sleep: 1 ZzZzzz, sleep: 2 ZzZzzz, sleep: 2 ZzZzzz, sleep: 2 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 ZzZzzz, sleep: 2 ### Done at: Thu Sep 1 14:11:14 2016
一共是用了14秒。
直接上代码:
#!/usr/bin/env python3 import threading from random import randint from time import sleep, ctime def hi(n): sleep(n) print("ZzZzzz, sleep: ", n) def main(): print("### Start at: ", ctime()) threads = [] for i in range(10): rands = randint(1,2) # 实例化每一个 Thread 对象,把函数和参数传递进去,返回 Thread 实例 t = threading.Thread(target=hi, args=(rands,)) threads.append(t) # 分配线程 for i in range(10): threads[i].start() # 开始执行多线程 for i in range(10): threads[i].join() # (自旋锁)等待线程结束或超时,而后再往下执行 print("### Done at: ", ctime()) if __name__ == '__main__': main()
运行结果:
### Start at: Thu Sep 1 14:18:00 2016 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 ZzZzzz, sleep: 2 ZzZzzz, sleep: 2 ZzZzzz, sleep: 2 ZzZzzz, sleep: 2 ### Done at: Thu Sep 1 14:18:02 2016
使用多线程,只用了2秒。
#!/usr/bin/env python3 import threading from random import randint from time import sleep, ctime class MyThread(threading.Thread): def __init__(self, func, args, times): super(MyThread, self).__init__() self.func = func self.args = args self.times = times def run(self): print("begin thread......", self.times) self.res = self.func(*self.args) print("end threads......", self.times) def hi(n): sleep(n) print("ZzZzzz, sleep: ", n) def main(): print("### Start at: ", ctime()) threads = [] for i in range(10): rands = randint(1,2) t = MyThread(hi, (rands,), i+1) threads.append(t) for i in range(10): threads[i].start() for i in range(10): threads[i].join() print("### Done at: ", ctime()) if __name__ == '__main__': main()
执行结果:
### Start at: Thu Sep 1 14:47:09 2016 begin thread...... 1 begin thread...... 2 begin thread...... 3 begin thread...... 4 begin thread...... 5 begin thread...... 6 begin thread...... 7 begin thread...... 8 begin thread...... 9 begin thread...... 10 ZzZzzz, sleep: 1 ZzZzzz, sleep: 1 end threads...... 1 end threads...... 4 ZzZzzz, sleep: 1 end threads...... 7 ZzZzzz, sleep: 1 end threads...... 3 ZzZzzz, sleep: 1 end threads...... 9 ZzZzzz, sleep: 2 end threads...... 2 ZzZzzz, sleep: 2 end threads...... 5 ZzZzzz, sleep: 2 ZzZzzz, sleep: 2 end threads...... 10 end threads...... 6 ZzZzzz, sleep: 2 end threads...... 8 ### Done at: Thu Sep 1 14:47:11 2016
这个栗子对 Thread 子类化,而不是对其实例化,使得定制线程对象更具灵活性,同时也简化线程建立的调用过程。
当多线程争夺锁时,容许第一个得到锁的线程进入临街区,并执行代码。全部以后到达的线程将被阻塞,直到第一个线程执行结束,退出临街区,并释放锁。须要注意,那些阻塞的线程是没有顺序的。
举个栗子:
#!/usr/bin/env python3 import threading from random import randint from time import sleep, ctime L = threading.Lock() # 引入锁 def hi(n): L.acquire() # 加锁 for i in [1,2]: print(i) sleep(n) print("ZzZzzz, sleep: ", n) L.release() # 释放锁 def main(): print("### Start at: ", ctime()) threads = [] for i in range(10): rands = randint(1,2) t = threading.Thread(target=hi, args=(rands,)) threads.append(t) for i in range(10): threads[i].start() for i in range(10): threads[i].join() print("### Done at: ", ctime()) if __name__ == '__main__': main()
运行上面的代码,再将锁的代码注释掉,对比下输出。