|
| 1 | +# encoding: utf-8 |
| 2 | +__author__ = 'zhanghe' |
| 3 | + |
| 4 | +import time |
| 5 | +import threading |
| 6 | + |
| 7 | +# 假定这是你的银行存款: |
| 8 | +balance = 0 |
| 9 | +lock = threading.Lock() |
| 10 | + |
| 11 | + |
| 12 | +def change_it(n): |
| 13 | + # 先存后取,结果应该为0: |
| 14 | + global balance |
| 15 | + balance = balance + n |
| 16 | + balance = balance - n |
| 17 | + |
| 18 | + |
| 19 | +def run_thread(n): |
| 20 | + for i in range(100000): |
| 21 | + change_it(n) |
| 22 | + |
| 23 | + |
| 24 | +def run_thread_lock(n): |
| 25 | + for i in range(100000): |
| 26 | + # 先要获取锁: |
| 27 | + lock.acquire() |
| 28 | + try: |
| 29 | + # 放心地改吧: |
| 30 | + change_it(n) |
| 31 | + finally: |
| 32 | + # 改完了一定要释放锁: |
| 33 | + lock.release() |
| 34 | + |
| 35 | + |
| 36 | +def run_without_lock(): |
| 37 | + """ |
| 38 | + 不带锁的主程序 |
| 39 | + :return: |
| 40 | + """ |
| 41 | + start_time = time.time() |
| 42 | + t1 = threading.Thread(target=run_thread, args=(5,)) |
| 43 | + t2 = threading.Thread(target=run_thread, args=(8,)) |
| 44 | + t1.start() |
| 45 | + t2.start() |
| 46 | + t1.join() |
| 47 | + t2.join() |
| 48 | + end_time = time.time() |
| 49 | + print end_time - start_time |
| 50 | + print balance |
| 51 | + |
| 52 | + |
| 53 | +def run_with_lock(): |
| 54 | + """ |
| 55 | + 带锁的主程序 |
| 56 | + :return: |
| 57 | + """ |
| 58 | + start_time = time.time() |
| 59 | + t1 = threading.Thread(target=run_thread_lock, args=(5,)) |
| 60 | + t2 = threading.Thread(target=run_thread_lock, args=(8,)) |
| 61 | + t1.start() |
| 62 | + t2.start() |
| 63 | + t1.join() |
| 64 | + t2.join() |
| 65 | + end_time = time.time() |
| 66 | + print end_time - start_time |
| 67 | + print balance |
| 68 | + |
| 69 | +if __name__ == '__main__': |
| 70 | + # 这是银行账户修改的简单例子,以下分别测试不加锁与加锁的运行情况 |
| 71 | + run_without_lock() |
| 72 | + # run_with_lock() |
| 73 | + |
| 74 | + |
| 75 | +''' |
| 76 | +run_without_lock()运行结果: |
| 77 | +0.209647893906 |
| 78 | +8(不固定) |
| 79 | +
|
| 80 | +run_with_lock()运行结果: |
| 81 | +0.441839933395 |
| 82 | +0 |
| 83 | +
|
| 84 | +可以看出,在有全局变量的情况下,需要用锁机制防止修改过程中的冲突 |
| 85 | +这样一来,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。 |
| 86 | +
|
| 87 | +Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核。 |
| 88 | +多线程的并发在Python中就是一个美丽的梦。 |
| 89 | +
|
| 90 | +多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。 |
| 91 | +Python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务。 |
| 92 | +多个Python进程有各自独立的GIL锁,互不影响。 |
| 93 | +
|
| 94 | +深入分析: |
| 95 | +一个任务在执行的过程中大部分时间都在等待IO操作, |
| 96 | +单进程单线程模型会导致别的任务无法并行执行, |
| 97 | +因此,我们才需要多进程模型或者多线程模型来支持多任务并发执行。 |
| 98 | +现代操作系统对IO操作已经做了巨大的改进,最大的特点就是支持异步IO |
| 99 | +如果充分利用操作系统提供的异步IO支持,就可以用单进程单线程模型来执行多任务, |
| 100 | +这种全新的模型称为事件驱动模型,Nginx就是支持异步IO的Web服务器, |
| 101 | +它在单核CPU上采用单进程模型就可以高效地支持多任务。 |
| 102 | +在多核CPU上,可以运行多个进程(数量与CPU核心数相同),充分利用多核CPU。 |
| 103 | +由于系统总的进程数量十分有限,因此操作系统调度非常高效。 |
| 104 | +
|
| 105 | +
|
| 106 | +处理多任务推荐的做法是: 多进程 + 协程 |
| 107 | +''' |
0 commit comments