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. css网格布局

    先来一段基本布局 <!doctype html> <html> <head> <meta charset="utf-8"> < ...

  2. KMP——从入门到不会打题

    KMP——从入门到不会打题 前言 如果你不了解哈希,建议先观看本蒟蒻的另一篇博客,对哈希有一定的理解   哈希大法吼 KMP算法,别名烤馍片或者看毛片,由烤馍片男子天团三位神犇同时发现的一种强大的单模 ...

  3. CentOS6.9安装MySQL5.6

    1 检查系统是否自带MySQL 检查系统是否自带MySQL yum list installed | grep mysql 下面结果说明系统自带MySQL 卸载系统自带MySQL yum -y rem ...

  4. 黑客最喜欢的15个Nmap扫描命令,熟练掌握你也能成为黑客大神

    1.针对IP或主机的基本Nmap扫描 nmap IP 现在,如果要扫描主机名,只需替换主机的IP,如下所示: nmap 域名 2.扫描本地或远程服务器上的特定端口或扫描整个端口范围 nmap -p 1 ...

  5. DataSet 反射转换成 List<T>

    /// <summary> /// DataSet转换成指定返回类型的实体集合 /// </summary> /// <typeparam name="T&qu ...

  6. 第31课 std::atomic原子变量

    一. std::atomic_flag和std::atomic (一)std::atomic_flag 1. std::atomic_flag是一个bool类型的原子变量,它有两个状态set和clea ...

  7. 为某金融企业开发团队分享DevOps Server流水线使用经验

    http://www.cnblogs.com/danzhang/  DevOps MVP 张洪君

  8. 路径规划基础A*算法

    1,Dijkstra’s  算法 一种发散性寻找最短路径算法. 由起点开始向四周开始发散,直到碰到目标点为止.这时就是最短路径.优点:能找到与目标点的最短路径:缺点:搜索花费的时间会比较长. 2,Gr ...

  9. Gitlab CI/CD

    Gitlab CI/CD 前言 纵观人类历史的发展以及三次工业革命,你会发现利用机器来替代部分人力劳动,将重复的工作自动化从而解放生产力都是发展的必然趋势,在软件工程领域也不例外,其中 CI/CD 就 ...

  10. Android添加新按键

    1.前言 在Android开发中可能会遇到添加新的按键的需求,本文将简单介绍如何在Android系统中完成一个新的按键的添加. 当系统有新的按键需要添加时,Linux内核下的键码到Android系统中 ...