1 什么是线程

  线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

  一个线程其实就是一堆指令集合。竞争式抢占CPU资源。 

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import time
 2 import threading
 3 
 4 begin = time.time()
 5 def foo(n):
 6     print('foo-%s' % n)
 7     time.sleep(1)
 8     print('end foo')
 9 
10 
11 def bar(n):
12     print('bar-%s' % n)
13     time.sleep(2)
14     print('end bar')
15 
16 
17 # foo()
18 # bar()
19 t1 = threading.Thread(target=foo, args=(1,))
20 t2 = threading.Thread(target=bar, args=(2,))
21 
22 t1.start()
23 t2.start()
24 print('----- in the main-----')
25 
26 t1.join()
27 t2.join()
28 
29 end = time.time()
30 print(end-begin)

线程

2 什么是进程

  进程是对线程资源的整合,一个程序实例。

  IO密集型任务或函数,计算密集型任务函数。

3 GIL

  同一时刻,只能有有一个线程进入解释器。即保证同一时刻只有一个线程对共享资源进行存取。

  在python中,如果处理任务是IO密集型,可用多线程;如果是计算密集型的,需要使用C语言。

4 进程与线程的区别

  进程里面的线程可共享数据。

  线程之间可通信,进程不能。

  进程创建通过拷贝,比较消耗CPU资源。

  join()在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

  setDaemon(True)与join()方法相反。守护主线程。

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import threading
 2 from time import ctime, sleep
 3 import time
 4 
 5 def music(func):
 6     for i in range(2):
 7         print('开始播放音乐%s. %s' % (func, ctime()))
 8         sleep(4)
 9         print('结束音乐播放%s' % ctime())
10 
11 
12 def move(func):
13     for i in range(2):
14         print('开始播放电影%s. %s' % (func, ctime()))
15         sleep(5)
16         print('结束电影播放%s' % ctime())
17 
18 
19 threads = []
20 t1 = threading.Thread(target=music, args=('七里香',))
21 threads.append(t1)
22 t2 = threading.Thread(target=move, args=('教父',))
23 threads.append(t2)
24 
25 
26 if __name__ == "__main__":
27     for t in threads:
28         t.setDaemon(True)  # 守护作用,子线程无论是否完成,都所主线程结束而结束
29         t.start()
30         # t.join()  # 没有线程效果
31     # t.join()  # t2执行完成后,才会执行下方代码
32     # t1.join()  # t1执行完成后,执行下方代码。
33     print(threading.current_thread())
34     print(threading.active_count())
35     print('播放结束%s' % ctime())

join()用法

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import threading
 2 import time
 3 
 4 class MyThread(threading.Thread):
 5     def __init__(self, num):
 6         threading.Thread.__init__(self)
 7         self.num = num
 8 
 9     # 定义每个线程要运行的函数
10     def run(self):
11         print("运行数字:%s" % self.num)
12         time.sleep(3)
13 
14 
15 if __name__ == '__main__':
16     t1 = MyThread(1)
17     t2 = MyThread(2)
18     t1.start()
19     t2.start()

线程的另一种调用方法

 5 同步锁

  同步锁也是保证同一时刻只有一个线程被执行。

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import time
 2 import threading
 3 
 4 
 5 def addNum():
 6     global num
 7     # num -= 1  # CPU还未切换,就已经减一操作了
 8     r.acquire()  # 获取锁对象
 9     temp = num  # 多个线程时,不安全,还未减一CPU就切换了
10     time.sleep(0.00001)
11     print('--get num:', num)
12     num = temp - 1
13     r.release()  # 释放锁对象
14 
15 
16 #
17 num = 100
18 thread_list = []
19 r = threading.Lock()  # 和join类似
20 for i in range(100):
21     t = threading.Thread(target=addNum)
22     t.start()
23     thread_list.append(t)
24 
25 for t in thread_list:
26     t.join()  #  join是等待线程结束再开启其它线程
27 
28 print('final num:', num)
29 # GIL保证同一时刻,保证只有一个线程进入解释器
30 # Lock避免CPU快速切换造成数据误差

同步锁

 6 递归锁和死锁

  死锁:再线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源。解决办法是使用递归锁。

  递归锁:threading.Rlock(),Rlock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release,其它的线程才能获得资源。

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import threading
 2 import time
 3 
 4 class MyThread(threading.Thread):
 5     def doA(self):
 6         lock.acquire()  # A
 7         print(self.name, 'gotlockA', time.ctime())
 8         time.sleep(3)
 9         # 内部已经A锁,为什么还要有B锁?
10         # 防止其它函数修改数据
11         lock.acquire()  # B
12         print(self.name, 'gotlockB', time.ctime())
13         lock.release()  # B
14         lock.release()  # A
15 
16     def doB(self):
17         lock.acquire()  # B
18         print(self.name, 'gotlockB', time.ctime())
19         time.sleep(2)
20         lock.acquire()  # A
21         print(self.name, 'gotlockA', time.ctime())
22         lock.release()  # A
23         lock.release()  # B
24 
25     def run(self):
26         self.doA()
27         time.sleep(1)
28         self.doB()
29 
30 
31 # 就如同进小区大门后锁小区大门,再进家门后锁家门
32 if __name__ == "__main__":
33     # lockA = threading.Lock()
34     # lockB = threading.Lock()
35     lock = threading.RLock()  # 递归锁,内部有计时器和锁两个东西
36     threads = []
37     for i in range(5):
38         threads.append(MyThread())
39     for t in threads:
40         t.start()
41     for t in threads:
42         t.join()

死锁和迭代锁

7 信号量

  信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数器,每当调用acquire()时-1,调用release()时+1。计数器不能小于0,当计数器为0时,acquire()将阻塞线程至同步锁定状态,知道其它线程调用release()。

  并行锁,开几把锁 ,就会有几个线程进锁。类似停车位,4个停车位只能进来停4辆车。

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import threading, time
 2 
 3 
 4 class MyThreaad(threading.Thread):
 5     def run(self):
 6         if semaphore.acquire():
 7             print(self.name)
 8             time.sleep(3)
 9             semaphore.release()
10 
11 
12 # 用处,限制多少个线程连接数据库
13 if __name__ == "__main__":
14     semaphore = threading.BoundedSemaphore(5)  # 决定有多少个线程
15     thrs = []
16     for i in range(13):
17         thrs.append(MyThreaad())
18     for t in thrs:
19         t.start()

信号量

8 条件变量同步(Condition)

  有一类线程需要满足条件后才能够继续执行,python提供了threading.Condition对象用于条件变量线程的支持,例如生产者和消费者模型

  lock_con = threading.Condition(Lock/Rlock),锁是可选项,不传人锁,对象自动创建一个Rlock()

    wait():条件不满足时调用,线程会释放锁并进入等待阻塞。

    notify():条件闯到后调用,通知等待池激活一个线程。

    notifyAlll():条件创造后调用,通知等待池激活所有线程。

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import threading, time
 2 from random import randint
 3 
 4 
 5 class Producer(threading.Thread):
 6     def run(self):
 7         global L
 8         while True:
 9             val = randint(0, 100)
10             print('生产者', self.name, ':Append'+str(val), L)
11             if lock_con.acquire():
12                 L.append(val)
13                 lock_con.notify()
14                 lock_con.release()
15             time.sleep(3)
16 
17 
18 class Consumer(threading.Thread):
19     def run(self):
20         global L
21         while True:
22             lock_con.acquire()
23             if len(L) == 0:
24                 lock_con.wait()
25             print('消费者', self.name, ':Delete'+str(L[0]), L)
26             del L[0]
27             lock_con.release()
28             time.sleep(0.25)
29 
30 
31 if __name__ == '__main__':
32     L = []
33     lock_con = threading.Condition()
34     threads = []
35     for i in range(5):
36         threads.append(Producer())
37     threads.append(Consumer())
38     for t in threads:
39         t.start()
40     for t in threads:
41         t.join()

生产者和消费者模型

9 同步条件(event)

  类似condition,不需要锁,比condition用的更广。

  event = threading.Event(),初始值为False

    event.isSet():返回event的状态值。

    event.wait():如果event.isSet() == False将阻塞线程

    event.set():设置event的状态值为True,所有的阻塞池的线程激活进入就绪状态,等待操作系统调度。

    event.clear():恢复event状态值为False

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import threading, time
 2 
 3 
 4 class Boss(threading.Thread):
 5     def run(self):
 6         print('Boss:今晚大家都要加班到22:00')
 7         event.isSet() or event.set()
 8         time.sleep(5)
 9         print('Boss:<22:00可以下班了>')
10         event.isSet() or event.set()
11 
12 
13 class Worker(threading.Thread):
14     def run(self):
15         event.wait()
16         print('Worker:要加班了')
17         time.sleep(0.25)
18         event.clear()
19         event.wait()
20         print('Worker:下班了')
21 
22 
23 if __name__ == '__main__':
24     event = threading.Event()
25     threads = []
26     for i in range(5):
27         threads.append(Worker())
28     threads.append(Boss())
29     for t in threads:
30         t.start()
31     for t in threads:
32         t.join()

加班模型

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import threading, time
 2 import random
 3 
 4 
 5 def light():
 6     if not event.isSet():
 7         event.set()
 8     count = 0
 9     while True:
10         if count < 10:
11             print('10绿灯亮')
12         elif count < 13:
13             print('13黄灯亮')
14         elif count < 20:
15             if event.isSet():
16                 event.clear()
17             print('20红灯亮')
18         else:
19             count = 0
20             event.set()
21         time.sleep(1)
22         count += 1
23 
24 
25 def car(n):
26     while True:
27         time.sleep(random.randrange(10))
28         if event.isSet():
29             print('car [%s] is running...' % n)
30         else:
31             print('car [%s] is waiting for red light..' % n)
32 
33 
34 if __name__ == '__main__':
35     event = threading.Event()
36     Light =threading.Thread(target=light)
37     Light.start()
38     for i in range(3):
39         t = threading.Thread(target=car, args=(i,))
40         t.start()

红绿灯模型

10 队列(queue)多线程利器

  队列是一种数据结构,它的优势是本身有一把锁。

  队列的模式:

    先进先出FIFO,类似管道,queue.Queue(maxsize)。

    先进后出LIFO,类似堆栈,queue.LifoQueue(maxsize).

    优先队列,queue.Priority(maxsize)。

  队列的方法:

    put(item, block),item为必须插入项目的值,block默认值为1,如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元,如果block为0,put()方法将引发Full异常。

    get([,block, timeout]),可选参数为block,默认为True。如果队列为空且block为True,get()就使调用吸纳成暂停,直至项目可用,如果队列为空且block为False,队列将引发Empty一场。timeout等待时间。

    qsize()返回队列大小。

    empty()如果队列为空,返回True,反之False。

    full(),如果队列满了,返回True,反之False。

    get_nowait(),相当get(False)。

    put_nowait(item) ,相当put(item, False)。

    task_done() ,在完成一项工作之后,task_done() 函数向任务已经完成的队列发送一个信号。

    join() 实际上意味着等到队列为空,再执行别的操作。 

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import threading, queue
 2 from time import sleep
 3 from random import randint
 4 
 5 
 6 class Production(threading.Thread):
 7     def run(self):
 8         while True:
 9             r = randint(0, 100)
10             q.put(r)
11             print('生产出来%s号包子' % r)
12             sleep(1)
13 
14 
15 class Proces(threading.Thread):
16     def run(self):
17         while True:
18             re = q.get()
19             print('吃掉%s号包子' % re)
20 
21 
22 if __name__ == "__main__":
23     q = queue.Queue(10)
24     threads = [Production(), Production(), Production(), Proces()]
25     for t in threads:
26         t.start()

吃包子模型

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import time, random
 2 import queue, threading
 3 
 4 
 5 q = queue.Queue()
 6 def Producer(name):
 7     count = 0
 8     while count < 20:
 9         time.sleep(random.randrange(3))
10         q.put(count)
11         print('生产者%s生产%s号包子..' % (name, count))
12         count += 1
13 
14 
15 def Consumer(name):
16     count = 0
17     while count < 20:
18         time.sleep(random.randrange(4))
19         if not q.empty():
20             data = q.get()
21             print(data)
22             print('消费者%s吃了%s号包子' % (name, data))
23         else:
24             print('没有包子可吃啊')
25         count += 1
26 
27 
28 p1 = threading.Thread(target=Producer, args=('A', ))
29 c1 = threading.Thread(target=Consumer, args=('B', ))
30 p1.start()
31 c1.start()

吃包子模型

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 import random, threading, time
 2 from queue import Queue
 3 
 4 
 5 class Producer(threading.Thread):
 6     def __init__(self, t_name, queue):
 7         threading.Thread.__init__(self, name=t_name)
 8         self.data = queue
 9 
10     def run(self):
11         for i in range(10):
12             randomnum = random.randint(1, 99)
13             print("%s: %s is producing %d to the queue!" % (time.ctime(), self.getName(), randomnum))
14             self.data.put(randomnum)
15             time.sleep(1)
16         print("%s: %s finished!" %(time.ctime(), self.getName()))
17 
18 
19 class Consumer_even(threading.Thread):
20     def __init__(self, t_name, queue):
21         self.data = queue
22 
23     def run(self):
24         while True:
25             try:
26                 val_even = self.data.get(1, 5)
27                 if val_even % 2 == 0:
28                     print("%s: %s is consuming. %d in the queue is consumed!" % (time.ctime(),self.getName(),val_even))
29                     time.sleep(2)
30                 else:
31                     self.data.put(val_even)
32                     time.sleep(2)
33             except:
34                 print("%s: %s finished!" % (time.ctime(), self.getName()))
35                 break
36 
37 
38 class Consumer_odd(threading.Thread):
39     def __init__(self, t_name, queue):
40         threading.Thread.__init__(self, name=t_name)
41         self.data = queue
42 
43     def run(self):
44         while True:
45             try:
46                 val_odd = self.data.get(1, 5)
47                 if val_odd %2 != 0:
48                     print("%s: %s is consuming. %d in the queue is consumed!" % (time.ctime(), self.getName(), val_odd))
49                     time.sleep(2)
50                 else:
51                     self.data.put(val_odd)
52                     time.sleep(2)
53             except:
54                 print("%s: %s finished!" % (time.ctime(), self.getName()))
55                 break
56 
57 
58 def main():
59     queue = Queue()
60     producer = Producer('Pro.', queue)
61     consumer_even = Consumer_even('Con_even.', queue)
62     consumer_odd = Consumer_odd('Con_odd.', queue)
63     producer.start()
64     consumer_even.start()
65     consumer_odd.start()
66     producer.join()
67     consumer_even.join()
68     consumer_odd.join()
69     print('所有线程执行完毕')
70 
71 
72 if __name__ == '__main__':
73     main()

吃包子模型

11 进程

  multiprocessing模块中Process类中调用

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # Process类调用
 2 
 3 from multiprocessing import Process
 4 import time
 5 
 6 
 7 def func(name):
 8     print('hello', name,time.ctime())
 9     time.sleep(1)
10 
11 
12 if __name__ == "__main__":  # 运行进程程序务必加上此句
13     p_list = []
14     for i in range(3):
15         p = Process(target=func, args=('alvin:%s' % i,))
16         p_list.append(p)
17         p.start()
18     for i in p_list:
19         i.join()
20     print("end")

Process类直接调用

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # 创建类式的调用
 2 from multiprocessing import Process
 3 import time
 4 
 5 
 6 class MyProcess(Process):
 7     def __init__(self):
 8         super(MyProcess, self).__init__()
 9 
10     def run(self):
11         time.sleep(1)
12         print('hello', self.name, time.ctime())
13 
14 
15 if __name__ == "__main__":
16     p_list = []
17     for i in range(3):
18         p = MyProcess()
19         p.start()
20         p_list.append(p)
21 
22     for p in p_list:
23         p.join()
24 
25     print('end')

类式的调用

  Process(group=None, target=None, name=None, args=(), kwargs={})

    方法:run();start()调用run()方法;join()阻塞当前上下文环境,直到调用此方法的进程终止或到达指定的timeout(可选参数);terminate()不管任务是否完成,立即停止工作进程;is_alive()返回进程是否在运行。

  进程的名字解析

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # 进程之间的关系
 2 from multiprocessing import Process
 3 import os
 4 import time
 5 
 6 
 7 def info(name):
 8     print('name:', name)
 9     print('父进程:', os.getppid())
10     print('当前进程:', os.getpid())
11     print('------------')
12     time.sleep(1)
13 
14 
15 def func(name):
16     info(name)
17 
18 
19 if __name__ == "__main__":
20     info('主进程')
21     p1 = Process(target=info, args=('alvin', ))
22     p2 = Process(target=func, args=('egon', ))
23     p1.start()
24     p2.start()
25 
26     p1.join()
27     p2.join()
28 
29     print('ending')

进程之间的关系

   进程之间通信

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # 进程间通讯队列Queues
 2 from multiprocessing import Process, Queue
 3 
 4 
 5 def func(q, n):
 6     q.put([42, n, 'hello'])
 7 
 8 
 9 if __name__ == "__main__":
10     q = Queue()
11     p_list = []
12     for i in range(3):
13         p = Process(target=func, args=(q, i))
14         p_list.append(p)
15         p.start()
16     print(q.get())
17     print(q.get())
18     print(q.get())
19     for i in p_list:
20         i.join()

队列Queues通信

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # 进程间通信Pipe
 2 from multiprocessing import Process, Pipe
 3 
 4 
 5 def func(conn):
 6     conn.send([42, None, 'hello'])
 7     print(conn.recv())
 8     conn.close()
 9 
10 
11 if __name__ == "__main__":
12     parent_conn, child_conn = Pipe()
13     p = Process(target=func, args=(child_conn,))
14     p.start()
15     print(parent_conn.recv())
16     parent_conn.send("hello")
17     p.join()

通道Pipe通信

   进程间数据共享

  Queue和pipe只是实现了数据交互,并没实现数据共享,即一个进程去更改另一个进程的数据

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # manager实现数据共享
 2 from multiprocessing import Process, Manager
 3 
 4 
 5 def func(d, l, n):
 6     d[n] = n
 7     d["name"] = "alvin"
 8     l.append(n)
 9 
10 
11 if __name__ == "__main__":
12     with Manager() as manager:
13         d = manager.dict()
14         l = manager.list(range(5))
15         p_list = []
16         for i in range(10):
17             p = Process(target=func, args=(d, l, i))
18             p.start()
19             p_list.append(p)
20         for res in p_list:
21             res.join()
22         print(d)
23         print(l)

manager实现数据共享

  进程池

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # 进程池
 2 from multiprocessing import Pool
 3 import time
 4 
 5 
 6 def foo(args):
 7     time.sleep(1)
 8     print(args)
 9 
10 
11 if __name__ == "__main__":
12     p = Pool(5)
13     for i in range(30):
14         p.apply_async(func=foo, args=(i,))
15     p.close()  # 等子进程执行完毕后关闭线程池
16     p.join()

进程池

 12 协程 

  协程优点:

    无需线程上下文切换的开销
    无需原子操作锁定及同步的开销
    方便切换控制流,简化编程模型
    高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
  协程缺点:

    无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # 协程的示例代码
 2 import time
 3 
 4 
 5 def consumer():
 6     r = ""
 7     while True:
 8         n = yield r
 9         if not n:
10             return
11         print("消费者正在消费%s" % n)
12         time.sleep(1)
13         r = '200 ok'
14 
15 
16 def produce(c):
17     next(c)
18     n = 0
19     while n < 5:
20         n = n + 1
21         print("生产者正在生产%s" % n)
22         cr = c.send(n)
23         print("生产者消费反馈:%s" % cr)
24     c.close()
25 
26 
27 if __name__ == "__main__":
28     c = consumer()
29     produce(c)

协程

   greenlet

    greenlet机制的主要思想是:生成器函数或者协程函数中的yield语句挂起函数的执行,直到稍后使用next()或send()操作进行恢复为止。可以使用一个调度器循环在一组生成器函数之间协作多个任务。greentlet是python中实现我们所谓的"Coroutine(协程)"的一个基础库。 

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # greenlet机制
 2 from greenlet import greenlet
 3 
 4 
 5 def test1():
 6     print(12)
 7     gr2.switch()
 8     print(34)
 9     gr2.switch()
10 
11 
12 def test2():
13     print(56)
14     gr1.switch()
15     print(78)
16 
17 
18 gr1 = greenlet(test1)
19 gr2 = greenlet(test2)
20 gr1.switch()

greenlet

python主进程如何知道线程是否崩溃 python 进程线程_同步锁

python主进程如何知道线程是否崩溃 python 进程线程_死锁_02

1 # 会用gevent.sleep()去切换协程,而是在执行到IO操作时,gevent自动切换
 2 from gevent import monkey
 3 monkey.patch_all()
 4 import gevent
 5 from urllib import request
 6 import time
 7 
 8 
 9 def func(url):
10     print('获取网址是:%s' % url)
11     resp = request.urlopen(url)
12     data = resp.read()
13     print("%d 字节从%s网址收到" % (len(data), url))
14 
15 
16 start = time.time()
17 gevent.joinall(
18     [gevent.spawn(func, "https://itk.org"),
19      gevent.spawn(func, "https://www.github.com/"),
20      gevent.spawn(func, "https://zhihu.com/")
21      ]
22 )
23 
24 print(time.time()-start)