进程与线程
1、进程
进程:正在进行的一个过程或者说一个任务。而负责执行任务则是cpu。
要以一个整体的形式暴露给操作系统管理,里面包含了对各种资源的调用,内存的管理,网络接口的调用等;对各种资源的管理集合,就可以称为进程
1.1 multiprocessing模块(多进程)
from multiprocessing import Process import time def work(name): print('task <%s> is runing' %name) time.sleep(2) print('task <%s> is done' % name) if __name__ == '__main__': # Process(target=work,kwargs={'name':'jun'}) p1=Process(target=work,args=('jun',)) p2=Process(target=work,args=('xun',)) p1.start() p2.start() print('主')
1.2 join
join等待线程执行完后,其他线程再继续执行(串行)
from multiprocessing import Process import time def work(name): print('task <%s> is runing' %name) time.sleep(3) print('task <%s> is done' % name) if __name__ == '__main__': p1=Process(target=work,args=('egon',)) p2=Process(target=work,args=('alex',)) p3=Process(target=work,args=('yuanhao',)) # p1.start() # p2.start() # p3.start() # # p1.join() #主进程等,等待p1运行结束 # p2.join() #主进程等,等待p2运行结束 # p3.join() #主进程等,等待p3运行结束 p_l = [p1, p2, p3] for p in p_l: p.start() for p in p_l: p.join() print('主') # p_l = [p1, p2, p3] # for p in p_l: # p.start() # p.join() # p1.start() # p1.join() # p2.start() # p2.join() # p3.start() # p3.join() # print('主')
1.3 Process对象的其他方法或属性
创建进程的类:
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动) 强调: 1. 需要使用关键字的方式来指定参数 2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
参数介绍:
group参数未使用,值始终为None target表示调用对象,即子进程要执行的任务 args表示调用对象的位置参数元组,args=(1,2,'egon',) kwargs表示调用对象的字典,kwargs={'name':'egon','age':18} name为子进程的名称
方法介绍:
p.start():启动进程,并调用该子进程中的p.run() p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁 p.is_alive():如果p仍然运行,返回True p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
属性介绍:
p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置 p.name:进程的名称 p.pid:进程的pid p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可) p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
实战
from multiprocessing import Process import time,os def work(): print('parent:%s task <%s> is runing' %(os.getppid(),os.getpid())) time.sleep(1000) print('parent:%s task <%s> is done' %(os.getppid(),os.getpid())) if __name__ == '__main__': p1=Process(target=work) p1.start() # p1.terminate() # time.sleep(3) # print(p1.is_alive()) # print(p1.name) # print(p1.pid) print('主',os.getpid(),os.getppid()) time.sleep(10000)
1.4 守护进程
主进程创建守护进程
其一:守护进程会在主进程代码执行结束后就终止
其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止
# from multiprocessing import Process # import time # def work(name): # print('task <%s> is runing' %name) # time.sleep(2) # print('task <%s> is done' % name) # # if __name__ == '__main__': # p1=Process(target=work,args=('egon',)) # p1.daemon = True # p1.start() # # print('主') #主进程代码运行完毕,守护进程就会结束 from multiprocessing import Process import time def foo(): print(123) time.sleep(1) print("end123") def bar(): print(456) time.sleep(3) print("end456") if __name__ == '__main__': p1=Process(target=foo) p2=Process(target=bar) p1.daemon=True p1.start() p2.start() print("main-------") #打印该行则主进程代码结束,则守护进程p1应该被终止,可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止
1.5 进程同步(锁)
进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,
竞争带来的结果就是错乱,如何控制,就是加锁处理
part1:多个进程共享同一打印终端
# from multiprocessing import Process,Lock # import time # def work(name,mutex): # mutex.acquire() # print('task <%s> is runing' %name) # time.sleep(2) # print('task <%s> is done' % name) # mutex.release() # # if __name__ == '__main__': # mutex=Lock() # p1=Process(target=work,args=('egon',mutex)) # p2=Process(target=work,args=('alex',mutex)) # p1.start() # p2.start() # print('主')
1.6 paramiko模块
1、介绍
paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。
2、 下载安装
pip3 install paramiko #在python3中
##python2中 pycrypto,由于 paramiko 模块内部依赖pycrypto,所以先下载安装pycrypto #在python2中 pip3 install pycrypto pip3 install paramiko 注:如果在安装pycrypto2.0.1时发生如下错误 command 'gcc' failed with exit status 1... 可能是缺少python-dev安装包导致 如果gcc没有安装,请事先安装gcc 在python2中
3. 使用
SSHClient
用于连接远程服务器并执行基本命令
基于用户名密码连接:
import paramiko # 创建SSH对象 ssh = paramiko.SSHClient() # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname='192.168.1.172', port=22, username='root', password='xxx') # 执行命令 stdin, stdout, stderr = ssh.exec_command('df') # 获取命令结果 result = stdout.read() print(result.decode('utf-8')) # 关闭连接 ssh.close()
基于公钥密钥连接:
客户端文件名:id_rsa
服务端必须有文件名:authorized_keys(在用ssh-keygen时,必须制作一个authorized_keys,可以用ssh-copy-id来制作)
import paramiko private_key = paramiko.RSAKey.from_private_key_file('/tmp/id_rsa') # 创建SSH对象 ssh = paramiko.SSHClient() # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接服务器 ssh.connect(hostname='192.168.1.172', port=22, username='root', pkey=private_key) # 执行命令 stdin, stdout, stderr = ssh.exec_command('df') # 获取命令结果 result = stdout.read() print(result.decode('utf-8')) # 关闭连接 ssh.close()
SFTPClient
用于连接远程服务器并执行上传下载
基于用户名密码上传下载
import paramiko transport = paramiko.Transport(('192.168.1.172',22)) transport.connect(username='root',password='xxx') sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put('/tmp/id_rsa', '/etc/test.rsa') # 将remove_path 下载到本地 local_path sftp.get('remove_path', 'local_path') transport.close()
2、线程
2.1什么是线程
在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程
车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线
流水线的工作需要电源,电源就相当于cpu
所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。
例如,北京地铁与上海地铁是不同的进程,而北京地铁里的13号线是一个线程,北京地铁所有的线路共享北京地铁所有的资源,比如所有的乘客可以被所有线路拉。
2.2 threading模块
线程创建有2种方式:如下
直接调用
import threading,time def run(n): print("test...",n) time.sleep(2) if __name__ == '__main__': t1 = threading.Thread(target=run,args=("t1",)) t2 = threading.Thread(target=run,args=("t2",)) # 两个同时执行,然后等待两秒程序结束 t1.start() t2.start() # 程序输出 # test... t1 # test... t2
继承式调用
import threading,time class MyThread(threading.Thread): def __init__(self,num): # threading.Thread.__init__(self) super(MyThread,self).__init__() self.num =num def run(self):#定义每个线程要运行的函数 print("running on number:%s" %self.num) time.sleep(2) if __name__ == '__main__': # 两个同时执行,然后等待两秒程序结束 t1 = MyThread(1) t2 = MyThread(2) t1.start() t2.start() # 程序输出 # running on number:1 # running on number:2
2.3 join
join等待线程执行完后,其他线程再继续执行(串行)
import threading,time def run(n,sleep_time): print("test...",n) time.sleep(sleep_time) print("test...done", n) if __name__ == '__main__': t1 = threading.Thread(target=run,args=("t1",2)) t2 = threading.Thread(target=run,args=("t2",3)) # 两个同时执行,然后等待t1执行完成后,主线程和子线程再开始执行 t1.start() t2.start() t1.join() # 等待t1 print("main thread") # 程序输出 # test... t1 # test... t2 # test...done t1 # main thread # test...done t2
2.4 线程的互斥锁
# from threading import Thread,Lock # import time # n=100 # def work(): # global n # mutex.acquire() # temp=n # time.sleep(0.1) # n=temp-1 # mutex.release() # # if __name__ == '__main__': # mutex=Lock() # l=[] # start=time.time() # for i in range(100): # t=Thread(target=work) # l.append(t) # t.start() # # for t in l: # t.join() # print('run time:%s value:%s' %(time.time()-start,n))
2.5 互斥锁与join的区别
# from threading import Thread,Lock # import time # n=100 # def work(): # time.sleep(0.05) # global n # temp=n # time.sleep(0.1) # n=temp-1 # # # if __name__ == '__main__': # start=time.time() # for i in range(100): # t=Thread(target=work) # t.start() # t.join() # # print('run time:%s value:%s' %(time.time()-start,n)) #互斥锁 from threading import Thread,Lock import time n=100 def work(): time.sleep(0.05) global n mutex.acquire() temp=n time.sleep(0.1) n=temp-1 mutex.release() if __name__ == '__main__': mutex=Lock() l=[] start=time.time() for i in range(100): t=Thread(target=work) l.append(t) t.start() for t in l: t.join() print('run time:%s value:%s' %(time.time()-start,n))
2.6 GIL与多线程性能讨论
#多进程: #优点:可以利用多核优势 #缺点:开销大 #多线程: #优点:开销小 #缺点:不能利用多核优势 # from threading import Thread # from multiprocessing import Process # import time # #计算密集型 # def work(): # res=1 # for i in range(100000000): # res+=i # # if __name__ == '__main__': # p_l=[] # start=time.time() # for i in range(4): # # p=Process(target=work) #6.7473859786987305 # p=Thread(target=work) #24.466399431228638 # p_l.append(p) # p.start() # for p in p_l: # p.join() # # print(time.time()-start) from threading import Thread from multiprocessing import Process import time #IO密集型 def work(): time.sleep(2) if __name__ == '__main__': p_l=[] start=time.time() for i in range(400): # p=Process(target=work) #12.104692220687866 p=Thread(target=work) #2.038116455078125 p_l.append(p) p.start() for p in p_l: p.join() print(time.time()-start)
2.7 死锁与递归锁
#多进程: #优点:可以利用多核优势 #缺点:开销大 #多线程: #优点:开销小 #缺点:不能利用多核优势 # from threading import Thread # from multiprocessing import Process # import time # #计算密集型 # def work(): # res=1 # for i in range(100000000): # res+=i # # if __name__ == '__main__': # p_l=[] # start=time.time() # for i in range(4): # # p=Process(target=work) #6.7473859786987305 # p=Thread(target=work) #24.466399431228638 # p_l.append(p) # p.start() # for p in p_l: # p.join() # # print(time.time()-start) from threading import Thread from multiprocessing import Process import time #IO密集型 def work(): time.sleep(2) if __name__ == '__main__': p_l=[] start=time.time() for i in range(400): # p=Process(target=work) #12.104692220687866 p=Thread(target=work) #2.038116455078125 p_l.append(p) p.start() for p in p_l: p.join() print(time.time()-start)
2.8 信号量
from threading import Thread,current_thread,Semaphore import time,random sm=Semaphore(5) def work(): sm.acquire() print('%s 上厕所' %current_thread().getName()) time.sleep(random.randint(1,3)) sm.release() if __name__ == '__main__': for i in range(20): t=Thread(target=work) t.start()
2.9 事件Event
通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。
import threading,time def light(): count = 0 while True: if count < 10: #红灯 print("\033[41;1m红灯\033[0m",10-count) elif count >= 10 and count < 30: #绿灯 event.set() # 设置标志位 print("\033[42;1m绿灯\033[0m",30-count) else: event.clear() #把标志位清空 count = 0 time.sleep(1) count +=1 def car(n): while True: if event.is_set(): print("\033[32;0m[%s]在路上飞奔.....\033[0m"%n) else: print("\033[31;0m[%s]等红灯等的花都谢了.....\033[0m" % n) time.sleep(1) if __name__ == "__main__": event = threading.Event() light = threading.Thread(target=light) light.start() car = threading.Thread(target=car,args=("tesla",)) car.start()
from threading import Thread,current_thread,Event import time event=Event() def conn_mysql(): count=1 while not event.is_set(): if count > 3: raise ConnectionError('链接失败') print('%s 等待第%s次链接mysql' %(current_thread().getName(),count)) event.wait(0.5) count+=1 print('%s 链接ok' % current_thread().getName()) def check_mysql(): print('%s 正在检查mysql状态' %current_thread().getName()) time.sleep(1) event.set() if __name__ == '__main__': t1=Thread(target=conn_mysql) t2=Thread(target=conn_mysql) check=Thread(target=check_mysql) t1.start() t2.start() check.start()
2.10 定时器
from threading import Timer def hello(n): print("hello, world",n) t = Timer(3, hello,args=(11,)) t.start() # after 1 seconds, "hello, world" will be printed
2.11 线程queue
import queue # q=queue.Queue(3) #队列:先进先出 # q.put(1) # q.put(2) # q.put(3) # # print(q.get()) # print(q.get()) # print(q.get()) # q=queue.LifoQueue(3) #堆栈:后进先出 # q.put(1) # q.put(2) # q.put(3) # # print(q.get()) # print(q.get()) # print(q.get()) q=queue.PriorityQueue(3) #数字越小优先级越高 q.put((10,'data1')) q.put((11,'data2')) q.put((9,'data3')) print(q.get()) print(q.get()) print(q.get())
2.12 进程池与线程池
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import os,time,random def work(n): print('%s is running' %os.getpid()) time.sleep(random.randint(1,3)) return n**2 if __name__ == '__main__': p=ProcessPoolExecutor() # objs=[] # for i in range(10): # obj=p.submit(work,i) # objs.append(obj) # p.shutdown() # for obj in objs: # print(obj.result()) obj=p.map(work,range(10)) p.shutdown() print(list(obj)) # from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # from threading import current_thread # import os,time,random # def work(n): # print('%s is running' %current_thread().getName()) # time.sleep(random.randint(1,3)) # return n**2 # # if __name__ == '__main__': # p=ThreadPoolExecutor() # objs=[] # for i in range(21): # obj=p.submit(work,i) # objs.append(obj) # p.shutdown() # for obj in objs: # print(obj.result()) #进程池 # import requests #pip3 install requests # import os,time # from multiprocessing import Pool # from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # 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 parse_page(obj): # dic=obj.result() # print('<%s> parse :%s' %(os.getpid(),dic['url'])) # time.sleep(0.5) # res='url:%s size:%s\n' %(dic['url'],len(dic['text'])) #模拟解析网页内容 # with open('db.txt','a') as f: # f.write(res) # # # if __name__ == '__main__': # # # p=Pool(4) # p=ProcessPoolExecutor() # urls = [ # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # ] # # # for url in urls: # # p.apply_async(get_page,args=(url,),callback=parse_page) # p.submit(get_page,url).add_done_callback(parse_page) # # p.shutdown() # print('主进程pid:',os.getpid()) #线程池 # import requests #pip3 install requests # import os,time,threading # from multiprocessing import Pool # from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor # def get_page(url): # print('<%s> get :%s' %(threading.current_thread().getName(),url)) # respone = requests.get(url) # if respone.status_code == 200: # return {'url':url,'text':respone.text} # # def parse_page(obj): # dic=obj.result() # print('<%s> parse :%s' %(threading.current_thread().getName(),dic['url'])) # time.sleep(0.5) # res='url:%s size:%s\n' %(dic['url'],len(dic['text'])) #模拟解析网页内容 # with open('db.txt','a') as f: # f.write(res) # # # if __name__ == '__main__': # # # p=Pool(4) # p=ThreadPoolExecutor(3) # urls = [ # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # 'http://www.baidu.com', # ] # # # for url in urls: # # p.apply_async(get_page,args=(url,),callback=parse_page) # p.submit(get_page,url).add_done_callback(parse_page) # # p.shutdown() # print('主进程pid:',os.getpid())