9-3 线程,线程池,守护线程,锁,协程

一 线程

# 什么是进程 :是计算机资源分配的最小单位
# 什么是线程
# 线程和进程的关系 :
# 每一个进程中都至少有一个线程
#开启100个线程
 1 import os
 2 import time
 3 from threading import Thread
 4 n=100
 5 def func(i):
 6     global n
 7     time.sleep(1)
 8     n-=1
 9     print(os.getpid(),'thread%s'%i)
10 l=[]
11 for i in range(100):
12     t=Thread(target=func,args=(i,))
13     t.start()
14     l.append(t)
15 for i in l:
16     i.join()
17 print(n)


n的结果是0

总结:

 #每个进程里至少有一个主线程负责执行代码
# 在主线程中可以再开启一个新的线程
# 在同一个进程中就有两个线程同时在工作了
# 线程才是CPU调度的最小单位
# 多个线程之间的数据时共享的

二 守护线程
# 主线程结束了之后守护线程也同时结束
# 守护线程会等待主线程完全结束之后才结束
from threading import Thread
import time
def foo():
    while True:
        print(123)
        time.sleep(1)
def bar():
    print(456)
    time.sleep(3)
    print('end456')
t1=Thread(target=foo)
t2=Thread(target=bar)
t1.daemon=True #foo是守护线程
t1.start()
t2.start()
print("main----") #主线程结束的地方

打印结果:
123
456
main----
123
123
end456

 三 锁(Lock)

1普通锁 lock

# 当你的程序中出现了取值计算再赋值的操作 数据不安全 —— 加锁
 1 from threading import Thread,Lock
 2 import time
 3 def work():
 4     global n
 5 
 6     lock.acquire()
 7     temp=n
 8     time.sleep(0.1)
 9     n=temp-1
10     lock.release()
11 if __name__ == '__main__':
12     lock = Lock()
13     n=100
14     l=[]
15     for i in range(10):
16         p=Thread(target=work)
17         l.append(p)
18         p.start()
19     for i in l:
20         i.join()
21     print(n)
22 
23 最后n的值为90

2 递归锁(Rlock)(很少用)

1 from threading import RLock
2 
3 lock = RLock()
4 lock.acquire()
5 lock.acquire()
6 print(123)
7 lock.release()
8 print(456)
9 lock.release()

总结:

# 普通的锁 在同一个线程中 只能acquire一次
# 所以当acquire两次的时候就容易出现死锁现象
# 出现了死锁现象可以使用递归锁去解决问题
# 但是本质上死锁的出现是因为逻辑的错误
# 因此我们更应该把注意力集中在解决逻辑错误
# 而不要在出现错误的时候直接用递归锁规避

递归锁并没有本质上解决死锁的问题

 

四 线程池(ThreadPoolExecutor)

1

 1 import time
 2 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
 3 def func(num):
 4     print(num)
 5     time.sleep(1)
 6     print(num)
 7 if __name__ == '__main__':
 8     t=ThreadPoolExecutor(20) #20个线程,每次处理20个
 9     for i in range(50):
10         t.submit(func,i) #异步提交命令
11     t.shutdown()#同join整个线程池
12     print('done')

2 回调函数(callback)

 1 # import time
 2 # import random
 3 # from concurrent.futures import ThreadPoolExecutor
 4 # from threading import current_thread
 5 # urls=[
 6 #         'https://www.baidu.com',
 7 #         'https://www.python.org',
 8 #         'https://www.openstack.org',
 9 #         'https://help.github.com/',
10 #         'http://www.sina.com.cn/'
11 #         'http://www.cnblogs.com/'
12 #         'http://www.sogou.com/'
13 #         'http://www.sohu.com/'
14 #     ]
15 #
16 # def analies(content):
17 #     print('分析网页',current_thread())
18 #     print(content.result())
19 #
20 #
21 # def get_url(url):
22 #     print('爬取网页',current_thread())
23 #     time.sleep(random.uniform(1,3))
24 #     # analies(url*10)
25 #     return url*10
26 #
27 # t = ThreadPoolExecutor(3)
28 # print('主线程',current_thread())
29 # for url in urls:
30 #     t.submit(get_url,url).add_done_callback(analies) #
#回调函数当执行了get_url之后,得到了一个url*10 ,然后在立即执行analies函数,并传给content参数

# concurrent.futures里面的 callback是由子线程做的
 五协程(gevent)
需要手动安装,第三方模块
安装 :pip3 install gevent
协程 把一个线程拆分成几个

# 协程 是程序级别调度
# 减轻了操作系统的负担、增强了用户对程序的可控性

特点是:只要遇到阻塞就会执行别的任务。例如:
from gevent import monkey;monkey.patch_all()
import gevent
import time
def eat(name):
    print('%s eat 1' %name)
    time.sleep(2)
    print('%s eat 2' %name)

def play(name):
    print('%s play 1' %name)
    time.sleep(1)
    print('%s play 2' %name)


g1=gevent.spawn(eat,'egon')
g2=gevent.spawn(play,'alex')
g1.join()
g2.join()
# gevent.joinall([g1,g2])#第二种写法
print('')
执行结果是:

egon eat 1
alex play 1
alex play 2
egon eat 2



例2:利用协程批量访问url
 1 from gevent import monkey;monkey.patch_all() #这个是必须加的否则gevent不识别time
 2 import gevent
 3 import requests
 4 import time
 5 
 6 def get_page(url):
 7     print('GET: %s' %url)
 8     response=requests.get(url)
 9     if response.status_code == 200:
10         print('%d bytes received from %s' %(len(response.text),url))
11 
12 
13 start_time=time.time()
14 gevent.joinall([
15     gevent.spawn(get_page,'https://www.python.org/'),
16     gevent.spawn(get_page,'https://www.yahoo.com/'),
17     gevent.spawn(get_page,'https://github.com/'),
18 ])
19 stop_time=time.time()
20 print('run time is %s' %(stop_time-start_time))

 

 




posted @ 2018-06-15 22:56  huningfei  阅读(552)  评论(0编辑  收藏  举报
levels of contents