python的GIL

In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

上面的核心意思就是,无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行

线程

1同步锁

2死锁, 递归锁

3:信号量和同步对象(了解)

4队列------生产者消费者模型

5进程

线程的基本调用

<python的线程与threading模块>

import threading  # 线程
import time def Hi(num):
print('hello %d' % num)
time.sleep(3) if __name__ == '__main__':
# 第一个参数是要执行的函数名,第二个是函数的参数(必须是可迭代对象)
t1 = threading.Thread(target=Hi, args=(10, )) # 创建一个线程对象
t1.start() # 开启线程
t2 = threading.Thread(target=Hi, args=(9, )) # 创建一个线程对象
t2.start() # 开启线程
print('ending....')
# 这就是并发的现象 # 并行:指的是两个或者多个事件在同一时刻发生(同时调用多核)
# 并发:指的是两个或者多个事件在同一时间间隔内发生(在一个核内快速的切换)

第二种调用方式

import threading
import time class MyThread(threading.Thread):
def __init__(self,num):
threading.Thread.__init__(self)
self.num = num def run(self):#定义每个线程要运行的函数 print("running on number:%s" %self.num) time.sleep(3) if __name__ == '__main__': t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start() print("ending......")

join和setDaemon

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 18-5-22 下午8:45
# @Author : LK
# @File : lesson2.py
# @Software: PyCharm import threading
import time def music():
print('begin listen music %s'%time.ctime())
# t = input('请输入内容>>>')
# time.sleep(3)
print('stop listen music %s'%time.ctime())
# print(t) def game():
print('begin to game %s'%time.ctime())
time.sleep(5)
print('stop to game %s'%time.ctime()) if __name__ == '__main__':
t1 = threading.Thread(target=music)
t2 = threading.Thread(target=game) t1.start()
t2.start() # t1.join() # join就是等待的意思,让该线程执行完毕后,在执行主线程
# t2.join() # 注意如果注释这一句,结果是什么 print('ending....') print(t1.getName()) # 获取线程名,

join

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 18-5-22 下午9:26
# @Author : LK
# @File : 守护线程.py
# @Software: PyCharm # 守护线程 就是:和主线程一起退出,如果主线程结束了,那么不管守护的线程,有没有执行完毕,都退出
import threading
import time def music():
print('begin listen music %s' % time.ctime())
time.sleep(3)
print('stop listen music %s' % time.ctime()) def game():
print('begin to game %s' % time.ctime())
time.sleep(5)
print('stop to game %s' % time.ctime()) t1 = threading.Thread(target=music)
t2 = threading.Thread(target=game)
threads = []
threads.append(t1)
threads.append(t2)
if __name__ == '__main__': # t1.setDaemon(True)
t2.setDaemon(True)
for t in threads:
t.start()
# t.setDaemon(True) # 守护线程, 就是和主线程一块结束
print('ending....')

setDaemon

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

setDaemon(True):

将线程声明为守护线程,必须在start() 方法调用之前设置, 如果不设置为守护线程程序会被无限挂起。这个方法基本和join是相反的。

当我们 在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行,那么当主线程完成

想退出时,会检验子线程是否完成。如 果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是 只要主线程

完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 用setDaemon方法啦

其他方法

# run():  线程被cpu调度后自动执行线程对象的run方法
# start():启动线程活动。
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。 threading模块提供的一些方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

同步锁lock

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 18-5-23 下午4:42
# @Author : LK
# @File : 同步锁.py
# @Software: PyCharm
import threading, time # 用多线程去调用一个每次减1的函数,里面让他停留一会就会切换cpu,模拟线程安全问题,引出同步锁(互斥锁) def sub():
global num
# 这样坐是0,因为num-=1 这个执行的很快,没有到达时间片切换就执行完了,每次取的都是不同的值
# num -= 1
# 如果这里让他停一会,就会发生,前面的一些拿到的值为100,然后开始停下来,让其他线程取值
# 取得值还可能是100, 再过几个线程,取的时候就是前面的线程执行完了(到达时间片切换了)
# 取得是就可能是其他值(前面几个线程执行后的结果),最终结果就不在是0
# 这就是线程安全问题,多个线程都在处理同一个数据,
# 如果处理的太慢(sleep)就会发生多个线程处理的值都是原始的值(多个线程处理一个值) # 处理方法: 就是在执行这三条语句时,不让cpu切换,知道处理完成时,再切换(同步锁)
'''
定义一个锁:lock = threading.Lock()
lock.acquire() # 锁起来(获取)
这里是要执行的语句,
lock.release() #释放
这里的不执行完,不切换cpu
'''
lock.acquire()
temp = num
time.sleep(0.001)
num = temp - 1
lock.release() num = 100
l = []
lock = threading.Lock()
for i in range(100):
t = threading.Thread(target=sub)
l.append(t)
t.start() for t in l:
t.join()
print(num)

同步锁(互斥锁)

死锁(递归锁)

#   产生死锁:
'''
第一个线程执行doLockA, 然后lockB, 执行完actionA, 都释放了
开始执行actionB,对B上锁,不允许切换cpu,与此同时第二个线程开始执行actionA,对A上锁
不允许切换cpu,两个线程同时需要对方的资源释放但是都没有释放,所以死锁
(就像你问我要个香蕉, 我问你要个苹果, 你说我先给你,我说你先给我,于是就死锁了)
'''
'''
解决方法:
用threading.RLock() 去替换锁A和锁B
rlock就是在内部实现一个计数器,在同一个线程中,加锁就+1,释放就减一,只要锁数大于0,
其他线程就不能申请锁,
就是执行过程就是:当A函数执行完之后,所有线程开始抢占资源,谁抢到谁开始执行,
比如线程2抢到, 线程2开始执行A函数,A没有执行完之前其他线程不能够继续执行
'''
 
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 18-5-23 下午8:33
# @Author : LK
# @File : 递归锁_死锁.py
# @Software: PyCharm
import threading, time # 产生死锁:
'''
第一个线程执行doLockA, 然后lockB, 执行完actionA, 都释放了
开始执行actionB,对B上锁,不允许切换cpu,与此同时第二个线程开始执行actionA,对A上锁
不允许切换cpu,两个线程同时需要对方的资源释放但是都没有释放,所以死锁
(就像你问我要个香蕉, 我问你要个苹果, 你说我先给你,我说你先给我,于是就死锁了)
''' class myThread(threading.Thread):
def actionA(self):
lockA.acquire()
print(self.name, 'doLockA', time.ctime())
time.sleep(3)
lockB.acquire()
print(self.name, 'doLockB', time.ctime())
lockB.release()
lockA.release() def actionB(self):
lockB.acquire()
print(self.name, 'doLockB', time.ctime())
time.sleep(1)
lockA.acquire()
print(self.name, 'doLockA', time.ctime())
lockA.release()
lockB.release() def run(self):
self.actionA()
time.sleep(0.5)
self.actionB() if __name__ == '__main__':
lockA = threading.Lock()
lockB = threading.Lock()
r_lock = threading.RLock()
'''
解决方法:
用threading.RLock() 去替换锁A和锁B
rlock就是在内部实现一个计数器,在同一个线程中,加锁就+1,释放就减一,只要锁数大于0,
其他线程就不能申请锁,
就是执行过程就是:当A函数执行完之后,所有线程开始抢占资源,谁抢到谁开始执行,
比如线程2抢到, 线程2开始执行A函数,A没有执行完之前其他线程不能够继续执行
''' threads = []
for i in range(5):
'''创建5个线程对象'''
threads.append(myThread())
for t in threads:
t.start()
for i in threads:
t.join()
print('ending.....')

死锁(递归锁)

信号量与同步对象

信号量, 也是一种锁的机制, 在那个递归锁中的同时事件的安全问题中
里面是多个线程同时抢占资源, 但是这个是只允许指定的个数,去抢占
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 18-5-24 下午4:45
# @Author : LK
# @File : 信号量.py
# @Software: PyCharm '''
信号量, 也是一种锁的机制, 在那个递归锁中的同时事件的安全问题中
里面是多个线程同时抢占资源, 但是这个是只允许指定的个数,去抢占
'''
import threading, time
class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(3)
semaphore.release() if __name__ == '__main__': # 信号量, 参数的意思是同时允许几个线程去执行
semaphore = threading.Semaphore(5) threads = []
for i in range(10):
threads.append(myThread()) for t in threads:
t.start()
for t in threads:
t.join()

信号量

同步对象

event

'''
event 同步对象标志位,就是在一个线程中设定后,在其他线程中也能捕获到
需求:一个boss类,一个worker类,
当boss对象执行后,worker才执行,就需要设置一个同步的标志位,用来判断
该执行那个线程
'''
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 18-5-23 下午9:38
# @Author : LK
# @File : 同步对象.py
# @Software: PyCharm '''
event 同步对象标志位,就是在一个线程中设定后,在其他线程中也能捕获到
需求:一个boss类,一个worker类,
当boss对象执行后,worker才执行,就需要设置一个同步的标志位,用来判断
该执行那个线程
'''
'''
执行过程:
刚开始有5个worker线程和1个boss线程执行,
当worker执行时,wait没有被设定,一直在阻塞,但是boss可以执行
于是设定event并开始等5秒, 同时5个worker中的标志位变了,可以继续执行了
1秒后,worker清除event标志,继续阻塞,又过了4秒boss又设置了,
同时worker又可以执行了
'''
import threading, time
class Boss(threading.Thread):
def run(self):
print(self.name,'boss今天大家要加班到22点')
print(event.isSet()) # false,判断是否标志
event.set()
time.sleep(5)
print(self.name,'boss: <22:00>可以下班了')
print(event.isSet())
event.set() class Worker(threading.Thread):
def run(self):
event.wait() # 一旦event被设定 就等同于pass, 不设定就阻塞等待被设定
print(self.name,'worker:哎呀生活苦呀,')
time.sleep(1)
event.clear()
event.wait()
print(self.name,'worker: oyear下班了') # 如果不用event的话,就可能导致worker先说话,但是需求是让boss先说话,
# 因为cpu是抢占的方式执行的,不会按照需求走,所以就要引入同步标志位event
if __name__ == '__main__':
event = threading.Event()
threads =[] # 创建5个worker线程,1个boss线程
for i in range(5):
threads.append(Worker())
threads.append(Boss()) for t in threads:
t.start()
for t in threads:
t.join()
print('ending....')

同步对象

队列----多线程常用方法

队列的引入

'''
用多个线程同时对列表进行删除最后一个值,
会报错, 是因为可能会有多个线程同时取到最后一个值,都进行删除,
就会报错, 解决方法:可以用锁,将其锁住,(相当于串行的执行), 或者用队列
'''
'''
l = [1,2,3,4,5]
def fun():
while 1:
if not l:
break
a = l[-1]
print(a)
time.sleep(1)
l.remove(a)
if __name__ == '__main__':
t1 = threading.Thread(target=fun, args=())
t2 = threading.Thread(target=fun, args=())
t1.start()
t2.start()
'''

队列的引入

Python Queue模块有三种队列及构造函数:
1、Python Queue模块的FIFO队列先进先出。 class queue.Queue(maxsize)
2、LIFO类似于堆,即先进后出。 class queue.LifoQueue(maxsize)
3、还有在一种是优先级队列级别越低越先出来。 class queue.PriorityQueue(maxsize)
import queue

#   创建一个队列,里面最多可以存放3个数据
q = queue.Queue(maxsize=3) # FIFO,先进先出
# 将一个值入队
q.put(10)
q.put(9)
q.put(8)
# 如果这里在加上一个put, 就是有4个数据入队,但是空间不够,就会一直阻塞,直到,队列有空间时(从队列中取出get)
# block参数默认是True, 如果改成False,当队列满的时候如果继续入队,就不会堵塞而是报错queue.Full
# q.put(9, block=False)
while 1:
'''
将一个值从队列中取出
q.get()
调用队列对象的get()
方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,
get()
就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。
'''
# 取完之后将会阻塞, block=Fales,如果队列为空时,继续出队,就会报错,queue.Empty
# get类似与put
data = q.get(block=False)
print(data)

调用一

# 先进后出  LIFO 类似与栈
import queue
# 先进后出 LIFO 类似与栈
q = queue.LifoQueue(maxsize=4)
q.put('你好')
q.put(123)
q.put({"name":"lucky"}) while 1:
data = q.get()
print(data)

调用二

# 还有在一种是优先级队列级别越低越先出来1级最低。class queue.PriorityQueue(maxsize)
import queue
q = queue.PriorityQueue(maxsize=3)
q.put([2,'你好'])
q.put([3,123,'aa'])
q.put([1,{"name":"lucky"}]) while 1:
data = q.get()
# print(data)
print(data[1]) # 只显示数据,

调用三

import queue
q = queue.Queue(maxsize=4)
q.put('a')
q.put('b')
q.put('c')
print(q.qsize()) # 打印当前队列的大小,现在队列中有几个值
print(q.full()) # 判断是否满
print(q.empty()) # 判断是否为空
# q.put_nowait(3) # 相当于q.put(3, block=Flase)
# q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
# q.join() 实际上意味着等到队列为空,再执行别的操作
while 1:
data = q.get()
print(data)
print(q.qsize()) # 打印当前队列的大小,现在队列中有几个值
print(q.full()) # 判断是否满
print(q.empty()) # 判断是否为空

队列的其他方法

进程的基本使用

多进程模块 multiprocessing

进程的使用和线程的使用和调用的方法基本一样

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 18-5-25 下午5:31
# @Author : LK
# @File : 测试进程和线程.py
# @Software: PyCharm
from threading import Thread
from multiprocessing import Process
import time def fun():
print(time.ctime())
if __name__ == '__main__':
threads = []
for i in range(1000):
# t = Thread(target=fun) # 线程
t = Process(target=fun) # 进程
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join()
from  multiprocessing import Process
import time def f(name):
time.sleep(1)
print('hello %s'%name, time.ctime()) if __name__ == '__main__':
p_list = []
for t in range(3):
p = Process(target=f, args=('luck',))
p_list.append(p) # 三个进程时在同一时刻开启的
for p in p_list:
p.start()
for p in p_list:
p.join() print('ending....')

进程的调用方法一

class myProcess(Process):
def __init__(self):
# 父类初始化, 不传参数不用写
super(myProcess, self).__init__()
def run(self):
time.sleep(1)
print(self.name,'hello ',time.ctime()) if __name__ == '__main__':
p_list = []
for i in range(3):
p_list.append(myProcess())
for p in p_list:
p.start()
for p in p_list:
p.join()

进程的调用方法二

查看进程号

#   查查看进程的id
# os.getppid()获得当前进程的父进程,os.getpid()获得当前进程
# os.getppid 是pycharm的进程号
'''
from multiprocessing import Process
import os
import time def info(title):
print("title:", title)
print('父进程 id:', os.getppid())
print('当前进程 id:', os.getpid())
# time.sleep(3) if __name__ == '__main__':
info('主进程')
time.sleep(1)
print("------------------")
p = Process(target=info, args=('lucky子进程',))
p.start()
p.join()
p_list = []
for i in range(3):
p = Process(target=info, args=('子进程%d' % i,))
p_list.append(p)
for p in p_list:
p.start()
for p in p_list:
p.join()

查看进程号,进程之间的关系理解

Process 类
构造方法: Process([group [, target [, name [, args [, kwargs]]]]])   group: 线程组,目前还没有实现,库引用中提示必须是None;
  target: 要执行的方法;
  name: 进程名;
  args/kwargs: 要传入方法的参数。 实例方法:   is_alive():返回进程是否在运行。   join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。   start():进程准备就绪,等待CPU调度   run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。   terminate():不管任务是否完成,立即停止工作进程 属性:   daemon:和线程的setDeamon功能一样   name:进程名字。 ''' from multiprocessing import Process
import time class myProcess(Process):
def __init__(self, args):
super(myProcess,self).__init__()
self.args = args
def fun(self):
time.sleep(1)
print(self.name, self.is_alive(), self.args, self.pid)
time.sleep(1) def run(self):
self.fun() if __name__ == '__main__':
p_list = []
for i in range(10):
# p = Process(target=fun, args=('子进程%d' % i,))
p_list.append(myProcess('子进程%d' % i))
# p_list[-2].daemon = True
# 因为这三个进程是同时执行的,所以这个属性不明显
for p in p_list:
p.start()
for p in p_list:
p.join()

进程模块的其他方法

进程间的通信

队列,这里的队列和线程里的队列调用方法不一样

#   什么是进程通信,为什么要进程通信
# 因为进程与进程之间是相互独立的,不像线程可以信息共享,要想让进程间相互信息共享,就要传参数(利用队列) from multiprocessing import Process, Queue # 进程队列
import time
import queue # 线程队列 # 主进程get数据,子进程put数据,
# 阻塞的原因是,这个队列的数据不共享,在子进程中队列和主进程的队列信息不共享,没有任何关系
# 结局方法,将队列作为参数传过去
# 注意在win上面不传参数不能运行,但是在linux下能运行
# 所以轻易不要用多进程,进行进程间通信时,会涉及到copy资源
# def fun(q):
# ''' 队列
def fun():
q.put(1)
q.put(2)
q.put(3)
print(id(q))
# print(q.empty())
# def fun2():
def fun2(q):
while 1:
# print(q.empty())
data = q.get()
print(data)
print(id(q)) if __name__ == '__main__':
# q = queue.Queue() # 线程队列,
q = Queue() # 进程队列
# p = Process(target=fun, args=(q,)) # 传参进行了copy占用资源
p = Process(target=fun)
p.start()
p.join()
p2 = Process(target=fun2)
p2 = Process(target=fun2, args=(q,))
p2.start()
p2.join()

管道

from multiprocessing import Pipe
def fun(child_conn):
child_conn.send([12, {"name":"yuan"}, 'hello'])
print('主进程说:',child_conn.recv())
print('子进程id',id(child_conn)) if __name__ == '__main__':
prepare_conn, child_conn = Pipe() # 双向管道
print('id:',id(prepare_conn), id(child_conn))
p = Process(target=fun, args=(child_conn,))
p.start()
print('子进程说:',prepare_conn.recv())
prepare_conn.send('你好')
print('主进程id',id(prepare_conn))
p.join()

Managers

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

 
Managers支持的数据类型
# A manager returned by Manager() will support types list, dict, Namespace,
# Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier,
# Queue, Value and Array. For example: from multiprocessing import Manager
# Queue和pipe只是实现了数据交互,并没实现数据共享,即一个进程去更改另一个进程的数据。
# 所以利用Managers 进行数据共享, 同样也需要传参 def fun(d, l, i):
d[i]='字典'+ str(i)
l.append(i)
# pass
if __name__ == '__main__':
with Manager() as manager:
d = manager.dict() # d = {} 创建一个字典
l = manager.list(range(5)) # l = range(5)
p_list = []
for i in range(5):
p = Process(target=fun,args=(d,l,i,))
p.start()
p_list.append(p)
for p in p_list:
p.join() print(d)
print(l)

Managers模块

进程同步

#   进程锁, lock
from multiprocessing import Process, Lock
import time def fun(i):
lock.acquire()
print('%d'%i)
lock.release()
if __name__ == '__main__':
lock = Lock()
for i in range(10):
p = Process(target=fun, args=(i,)).start()

进程同步,锁

进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,
如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:
apply 同步
apply_async 异步(常用)

在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。多进程是实现并发的手段之一,需要注意的问题是:

  1. 很明显需要并发执行的任务通常要远大于核数
  2. 一个操作系统不可能无限开启进程,通常有几个核就开几个进程
  3. 进程开启过多,效率反而会下降(开启进程是需要占用系统资源的,而且开启多余核数目的进程也无法做到并行)

例如当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个。。。手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。

我们就可以通过维护一个进程池来控制进程数目,比如httpd的进程模式,规定最小进程数和最大进程数... 
ps:对于远程过程调用的高级应用程序而言,应该使用进程池,Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,就重用进程池中的进程。

 

'''
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,
如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:
apply 同步
apply_async 异步(常用)
'''
from multiprocessing import Process, Pool
import time, os def foo(i):
time.sleep(1)
print('子进程:',os.getpid(),i)
return 'Hello %s'%i
def bar(args):
# print('',os.getpgid())
print(args)
print('主进程:',os.getpid()) if __name__ == '__main__':
pool = Pool(5) # 进程池中开5个进程, 有100个任务需要执行, 每次执行5个
print('main :',os.getpid())
for i in range(100):
# 回调函数:某个动作或者 函数执行成功后,再去执行的函数
# pool.apply_async(func=foo, args=(i,))
# bar作为回调函数, 每次执行一个进程后都会执行回调函数, 回调函数是主进程中调用的
# func中函数的返回值,传给回调函数做参数
pool.apply_async(func=foo, args=(i,), callback=bar)
# close和join必须加,而且顺序固定
pool.close()
pool.join()

进程池

回调函数

 回掉函数:

需要回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数

我们可以把耗时间(阻塞)的任务放到进程池中,然后指定回调函数(主进程负责执行),这样主进程在执行回调函数时就省去了I/O的过程,直接拿到的是任务的结果。

from multiprocessing import Pool
import requests
import json
import os def get_page(url):
print('<进程%s> get %s' %(os.getpid(),url))
respone=requests.get(url)
if respone.status_code == 200:
return {'url':url,'text':respone.text} def pasrse_page(res):
print('<进程%s> parse %s' %(os.getpid(),res['url']))
parse_res='url:<%s> size:[%s]\n' %(res['url'],len(res['text']))
with open('db.txt','a') as f:
f.write(parse_res) if __name__ == '__main__':
urls=[
'https://www.baidu.com',
'https://www.python.org',
'https://www.openstack.org',
'https://help.github.com/',
'http://www.sina.com.cn/'
] p=Pool(3)
res_l=[]
for url in urls:
res=p.apply_async(get_page,args=(url,),callback=pasrse_page)
res_l.append(res) p.close()
p.join()
print([res.get() for res in res_l]) #拿到的是get_page的结果,其实完全没必要拿该结果,该结果已经传给回调函数处理了

进程池应用

协程

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 18-5-26 上午10:19
# @Author : LK
# @File : 协程.py
# @Software: PyCharm
from greenlet import greenlet # 优缺点
'''
def test1():
print(12)
g2.switch() # 切换到g2
print(24)
g2.switch() # 切换到g2
def test2():
print(56)
g1.switch() # 切换到g1
print(65)
g1.switch() if __name__ == '__main__':
g1 = greenlet(test1)
g2 = greenlet(test2)
g2.switch() '''
'''
import gevent import requests,time start=time.time() def f(url):
print('GET: %s' % url)
resp =requests.get(url)
data = resp.text
f = open('new.html', 'w', encoding='utf-8')
f.write(data)
f.close()
print('%d bytes received from %s.' % (len(data), url)) # 这就相当于一个协程, 每次进行读写操作阻塞时,都会切换cpu
gevent.joinall([ gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://www.baidu.com/'),
gevent.spawn(f, 'https://www.sina.com.cn/'), ]) # f('https://www.python.org/')
#
# f('https://www.yahoo.com/')
#
# f('https://baidu.com/')
#
# f('https://www.sina.com.cn/') print("cost time:",time.time()-start) '''
# import threading, gevent
# def fun():
# a = input('>>>')
# print(a)
# def fun2():
# print('\nhello')
# # gevent.joinall([
# #
# # gevent.spawn(fun()),
# # gevent.spawn(fun2()),
# # ])
# if __name__ == '__main__':
# # t1 = threading.Thread(target=fun).start()
# # t2 = threading.Thread(target=fun2).start()
# gevent.joinall([
#
# gevent.spawn(fun),
# gevent.spawn(fun2),
# ])

未完整

协程参考:

http://www.cnblogs.com/linhaifeng/articles/7429894.html

协程,协作式----- 非抢占式的程序

自己调动

Yield(协程)

用户态的切换呢

关键点在哪一步切换

协程主要解决的是io操作

协程:本质上就是一个线程

协程的优势:

1:没有切换的消耗

2:没有锁的概念

但是不能用多核,所以用多进程+协程,是一个很好的解决并发的方案

驱动事件

@font-face{ font-family:"Times New Roman"; } @font-face{ font-family:"宋体"; } p.MsoNormal{ mso-style-name:正文; mso-style-parent:""; margin:0pt; margin-bottom:.0001pt; mso-pagination:none; text-align:left; font-family:'Times New Roman'; font-size:12.0000pt; mso-font-kerning:1.0000pt; } span.msoIns{ mso-style-type:export-only; mso-style-name:""; text-decoration:underline; text-underline:single; color:blue; } span.msoDel{ mso-style-type:export-only; mso-style-name:""; text-decoration:line-through; color:red; } @page{mso-page-border-surround-header:no; mso-page-border-surround-footer:no;}@page Section0{ } div.Section0{page:Section0;}

Io多路复用

Select 触发方式

1:水平处罚

2:边缘触发

3:IO多路复用优势:同时可以监听多个链接

Select  负责监听

IO多路复用:

Select  那个平台都有

Poll

Epoll 效率最高

python之线程和进程(并发编程)的更多相关文章

  1. 操作系统/应用程序、操作中的“并发”、线程和进程,python中线程和进程(GIL锁),python线程编写+锁

    并发编程前言: 1.网络应用 1)爬虫 直接应用并发编程: 2)网络框架 django flask tornado 源码-并发编程 3)socketserver 源码-并发编程 2.运维领域 1)自动 ...

  2. Python之线程、进程和协程

    python之线程.进程和协程 目录: 引言 一.线程 1.1 普通的多线程 1.2 自定义线程类 1.3 线程锁 1.3.1 未使用锁 1.3.2 普通锁Lock和RLock 1.3.3 信号量(S ...

  3. Python 中线程和进程

    目录 线程和进程 一. 什么是进程 / 线程 1. 引论 2. 线程 3. 进程 4. 区别 5. 使用 二. 多线程使用 1. 常用方法 2. 常用参数 3. 多线程的应用 3.1 重写线程法 3. ...

  4. Python之线程与进程

    今天我们来了解一下Python的线程和进程的管理机制 首先,我们要了解下线程跟进程的概念: 线程(Thread)是操作系统能够进行运算调度的最小的单位,是一堆cpu的指令.他被包含在进程中,是进程中的 ...

  5. python中线程和进程的简单了解

    python中线程和进程的简单了解   一.操作系统.应用程序 1.硬件:硬盘.cpu.主板.显卡........ 2.装系统(本身也是一个软件): 系统就是一个由程序员写出来的软件,该软件用于控制计 ...

  6. Python自动化 【第九篇】:Python基础-线程、进程及python GIL全局解释器锁

    本节内容: 进程与线程区别 线程 a)  语法 b)  join c)  线程锁之Lock\Rlock\信号量 d)  将线程变为守护进程 e)  Event事件 f)   queue队列 g)  生 ...

  7. python之线程、进程

    线程语法 class Thread(_Verbose): """A class that represents a thread of control. This cla ...

  8. Python基础—线程、进程和协程

    今天已是学习Python的第十一天,来干一碗鸡汤继续今天的内容,今天的鸡汤是:超越别人对你的期望.本篇博客主要介绍以下几点内容: 线程的基本使用: 线程的锁机制: 生产者消费之模型(队列): 如何自定 ...

  9. python的线程和进程

    1.线程的基本概念 概念 线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程 ...

随机推荐

  1. 8.Vue的slot

    1.什么是slot 在  Vue.js  中我们使用  <slot>  元素作为承载分发内容的出口,作者称其为 插槽,可以应用在组合组件的场景中 2.使用 建立组件预留插槽 定义填充入插槽 ...

  2. [LeetCode] 215. Kth Largest Element in an Array 数组中第k大的数字

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

  3. linux写shell注意的问题

    linux写shell注意的问题一定要vi crontab.sh来写 ps:在windows系统中编辑过这个文件,就会出现类似的换行符 这样导致linux系统中运行sh报错 比如会出现$MQ字符 如果 ...

  4. centos7上配置mysql8的双主互写

    注意:1.主库1:10.1.131.75,主库2:10.1.131.762.server-id必须是纯数字,并且主从两个server-id在局域网内要唯一. [主节点1]vi /etc/my.cnf[ ...

  5. ArrayList 源码分析 基于jdk1.8:

    1:数据结构: transient Object[] elementData;  //说明内部维护的数据结构是一个Object[] 数组 成员属性: private static final int ...

  6. scala中nothing和null的区别

    1:nothing是所有类型的子类,他没有具体的实例对象,常见的应用:抛出异常.程序exit.无线循环等. 2:nothing是所有类型的子类,也是null的子类,nothing没有对象,但是可以用来 ...

  7. logstash之mongodb-log

    1.logstash6.5.3 配置收集mongodb的日志: 首先在mongodb服务器上部署filebeat收集日志并上传到logstash进行处理,然后上传到ES. filebeat-conf: ...

  8. WebStrom安装Markdown插件

    安装步骤 File→Settings→Plugins→关键字搜索markdown→选择Markdown Navigator→点击Install→出现下载弹窗,等待下载完毕→重启Webstrom 效果预 ...

  9. 一个小巧,也很nice的“小日历”--一个Android App

    一个小巧也很Nice的“小日历” 背景 因为,常用日历记一些事情,Android自带的日历,如果有事情,会显示一个小点,然后点击进去后才能看到事情的具体内容,不是很方便. 所以,写了一个“小日历” 特 ...

  10. 【05】Jenkins:用户权限管理

    写在前面的话 在一个企业研发部门内部,可能存在多个运维人员,而这些运维人员往往负责不同的项目,但是有可能他们用的又是同一个 Jenkins 的不同用户.那么我们就希望实现一个需求,能够不同的用户登录 ...