必威-必威-欢迎您

必威,必威官网企业自成立以来,以策略先行,经营致胜,管理为本的商,业推广理念,一步一个脚印发展成为同类企业中经营范围最广,在行业内颇具影响力的企业。

UDP是无连接不可靠的数据报协议必威:,为了能

2019-10-20 22:33 来源:未知

asyncio模块是python之父写的模块,按说应该是可相信的,python3.6本子定义为稳定版本。

python四线程socket编制程序之多顾客端连接,pythonsocket

Python中落实socket通讯的服务端相比较复杂,而客商端非常轻便,所以客商端基本上都以用sockct模块实现,而服务
端用有广大模块可以应用,如下:

必威 1

1、客户端

#!/usr/bin/env python
#coding:utf-8
'''
file:client.py
date:9/9/17 3:43 PM
author:lockey
email:[email protected]
desc:socket编程客户端,python3.6.2
'''
import socket,sys
HOST = '192.168.1.6'
PORT = 8998
ADDR =(HOST,PORT)
BUFSIZE = 1024

sock = socket.socket()
try:
 sock.connect(ADDR)
 print('have connected with server')

 while True:
  data = input('lockey# ')
  if len(data)>0:
  print('send:',data)
  sock.sendall(data.encode('utf-8')) #不要用send()
  recv_data = sock.recv(BUFSIZE)
  print('receive:',recv_data.decode('utf-8'))
  else:
  sock.close()
  break
except Exception:
 print('error')
 sock.close()
 sys.exit()

2、SocketServer模块

为了能够让八个客商端同期连接服务并拓宽通讯,服务端将使用SocketServer模块来达成,那样的话客户不用在子线程结束后,利用父进度对它举办管理,也不用关爱socket的关门,旭日东升切都由SocketServer来达成。

#!/usr/bin/env python
#coding:utf-8
'''
file:client.py
date:9/9/17 3:43 PM
author:lockey
email:[email protected]
desc:socket编程服务器端,python3.6.2
'''
from socketserver import BaseRequestHandler,ThreadingTCPServer
import threading

BUF_SIZE=1024

class Handler(BaseRequestHandler):
 def handle(self):
  address,pid = self.client_address
  print('%s connected!'%address)
  while True:
   data = self.request.recv(BUF_SIZE)
   if len(data)>0:
    print('receive=',data.decode('utf-8'))
    cur_thread = threading.current_thread()
    #response = '{}:{}'.format(cur_thread.ident,data)
    self.request.sendall('response'.encode('utf-8'))
    print('send:','response')
   else:
    print('close')
    break

if __name__ == '__main__':
 HOST = '192.168.1.6'
 PORT = 8998
 ADDR = (HOST,PORT)
 server = ThreadingTCPServer(ADDR,Handler) #参数为监听地址和已建立连接的处理类
 print('listening')
 server.serve_forever() #监听,建立好TCP连接后,为该连接创建新的socket和线程,并由处理类中的handle方法处理
 print(server)

以下测验中本身动用别的后生可畏台主机和本机的两在那之中断去老是服务器,都得以健康连接并且能开展多少应答交互

必威 2

瞩目:此程序示例运维平台为rhel7.2.x86_64,python版本为3.6.2,对于windows平台和非同风流倜傥python版本的用户可能非常不足一定的宽容性,假使是任何平台客商请自行校勘!!

上述正是本文的全体内容,希望对我们的学习抱有利于,也期望咱们多多点拨帮客之家。

Python中落到实处socket通讯的服务端相比复杂,而顾客端特轻易,所以顾客端基本上都是用so...

事先大家学了众多种经营过间的通讯,多进度并发等等,前些天大家来学学线程,线程和进度是哪些关联,进程和线程有哪些同样而又有哪些两样前几日就来发布那些答案。

目录

一、开启线程的两种方式
    1.1 直接利用利用threading.Thread()类实例化
    1.2 创建一个类,并继承Thread类
    1.3 在一个进程下开启多个线程与在一个进程下开启多个子进程的区别
        1.3.1 谁的开启速度更快?
        1.3.2 看看PID的不同
        1.3.3 练习
        1.3.4 线程的join与setDaemon
        1.3.5 线程相关的其他方法补充

二、 Python GIL
    2.1 什么是全局解释器锁GIL
    2.2 全局解释器锁GIL设计理念与限制

三、 Python多进程与多线程对比
四、锁
    4.1 同步锁
    GIL vs Lock
    4.2 死锁与递归锁
    4.3 信号量Semaphore
    4.4 事件Event
    4.5 定时器timer
    4.6 线程队列queue

五、协程
    5.1 yield实现协程
    5.2 greenlet实现协程
    5.3 gevent实现协程

六、IO多路复用

七、socketserver实现并发
    7.1 ThreadingTCPServer

八、基于UDP的套接字

本篇内容

  1. udp公约套接字
  2. 张开进度的不二诀窍
  3. 多进度完成产出的套接字通信
  4. join方法
  5. 护理进度
  6. 同步锁
  7. 进度队列
  8. 劳动者花费者模型
  9. 进程池
  10. paramiko模块

 

说明书:

 

大器晚成、开启线程的二种艺术

在python中展开线程要导入threading,它与开启进度所急需导入的模块multiprocessing在动用上,有非常大的相似性。在接下去的选择中,就足以窥见。

同开启进度的二种艺术同样:

生龙活虎、 udp契约套接字

1.TCP和UDP在传输层分歧:
UDP是无连接不可信的多少报公约。TCP提供面向连接的可信字节流。

2.利用UDP常见应用:
DNS(域名系列),NFS(互联网文件系统),SNMP(轻巧网络处理合同)。

3.代码应用:

服务端:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

import socketserver
class MyUDPhandler(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request)
        self.request[1].sendto(self.request[0].upper(),self.client_address)

if __name__ == '__main__':
    s = socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyUDPhandler)
    s.serve_forever()

 客户端:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

from socket import *

udp_client = socket(AF_INET,SOCK_DGRAM)

while True:
    msg=input('>>: ').strip()
    udp_client.sendto(msg.encode('utf-8'),('127.0.0.1',8080))
    data,server_addr = udp_client.recvfrom(1024)
    print(data.decode('utf-8'))

 注意:但这种办法并无法操纵客商端的出现数量,并发多少达到一定数额后,服务端会down掉,解决办法后续会提供。

 

粗粗定义:该模块提供了利用协程编写单线程并发代码,通过套接字和任何能源复用I​​ / O访问,运营网络客户端和服务器以至别的连锁原语的底子结构。

本篇导航:

1.1 直接利用利用threading.Thread()类实例化

from threading import Thread
import time
def sayhi(name):
    time.sleep(2)
    print('%s say hello' %name)

if __name__ == '__main__':
    t=Thread(target=sayhi,args=('egon',))
    t.start()

    print('主线程')

二、开启进度的法子

打开进度的点子分为三种:

(1)利用模块开启进度:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

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=('xiaolan',))
    p2 = Process(target=work,args=('xiaohong',))
    p1.start()
    p2.start()
    print('主程序')

 (2)利用类开启进程:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

from multiprocessing import Process
import time

class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name = name

    def run(self):
        print('task <%s> is runing' % self.name)
        time.sleep(2)
        print('task <%s> is done' % self.name)

if __name__ == '__main__':
    p = MyProcess('xiaolan')
    p.start()
    print('主程序')

 

简单易行利用(基于wsgi的报告急方器)

  • 线程概论
  • python的面世编制程序之多线程
  • Python GIL(Global Interpreter Lock)

1.2 创立二个类,并接二连三Thread类

from threading import Thread
import time
calss Sayhi(Thread):
    def __init__(self,name):
        super().__init__()
        self.name = name
    def run(self):
        time.sleep(2)
        print("%s say hello" %self.name)

if __name__ == "__main__":
    t = Sayhi("egon")
    t.start()
    print("主线程")

三、多进度达成产出的套接字通讯

听他们说刚刚学习的张开进度的法子,我们就用经过的办法来打开贰个互连网通讯。

服务端:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

from multiprocessing import Process
from socket import *

s = socket(AF_INET,SOCK_STREAM)
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(('127.0.0.1',8080))
s.listen(5)

def talK(conn,addr):
    while True:
        try:
            data=conn.recv(1024)
            if not data:break
            conn.send(data.upper())
        except Exception:
            break
    conn.close()

if __name__ == '__main__':
    while True:
        conn,addr = s.accept()
        p=Process(target=talK,args=(conn,addr))
        p.start()

    s.close()

 客户端:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

from socket import *

c = socket(AF_INET,SOCK_STREAM)
c.connect(('127.0.0.1',8080))

while True:
    msg = input('>>: ').strip()
    if not msg:continue
    c.send(msg.encode('utf-8'))
    data = c.recv(1024)
    print(data.decode('utf-8'))

c.close()

 

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 # @Time    : 2018/8/21 10:40
 4 # @Author  : WangYue
 5 # @Site    : 
 6 # @File    : alertor_uwsgi.py
 7 # @Software: PyCharm
 8 
 9 #加入环境变量避免程序报错
10 import sys,os
11 sys.path.append(os.path.dirname(os.path.dirname(__file__)))
12 
13 #引入wsgi模型,这里主要是弄一个简单的http模型来说明asyncio的简单使用
14 from wsgiref.simple_server import make_server
15 
16 #引入asyncio
17 import asyncio
18 
19 #引入其他可能的依赖
20 from threading import Thread
21 import json
22 
23 #引入本程序其他的内容,与asyncio无关是程序业务的其他部分
24 from conf.alertor_conf import ALERTOR_CONFIG
25 from model.alert_method_class import SendMail
26 
27 #定义一个运行asyncio loop 的线程,去单独运行它
28 def start_loop(loop):
29     asyncio.set_event_loop(loop)
30     loop.run_forever()
31 new_loop = asyncio.new_event_loop() #这个new_loop将会用于运行异步程序
32 t = Thread(target=start_loop, args=(new_loop,))
33 t.start() #利用多线程,额外起一个线程运行asyncio loop然后它在自身使用协程之类处异步处理业务
34 
35 
36 #这是wsgi主业务程序,application是wsgi的入口程序,wsgi就规定了这么个函数名,这样写wsgi就认可它是入口了。传参也是wsgi的规定,第一个是环境,第二个是响应
37 def application(env,start_res):
38     res_headers=[('Content-type', 'text/plain')]
39     if env["REQUEST_METHOD"]=='POST':
40         # the environment variable CONTENT_LENGTH may be empty or missing
41         try:
42             if env['PATH_INFO'] != "/send_alert":
43                 status = "404 func is not in use"
44                 start_res(status, res_headers)
45                 return [b"func is not in use"]
46 
47             request_body_size = int(env.get('CONTENT_LENGTH', 0))
48             status = "200 OK"
49             request_body = env['wsgi.input'].read(request_body_size)
50             print("post_info -->", request_body.decode())
51             r_body=json.loads(request_body.decode())
52             #就这里一行代码,new_loop.call_soon_threadsafe(),告诉asyncio去运行第一个参数的函数名,后边的参数是被运行函数的传参,有多少就传参多少个,这是异步的,非阻塞的。
53             new_loop.call_soon_threadsafe(SendMail.sendEmail,"Alertor Alarm level:"+r_body["level"]+"  server: "+r_body["server"],r_body)
54             start_res(status,res_headers)
55             return [b"ok send alert......."]
56         except (ValueError):
57             status = "404 json data not found key"
58             request_body_size = 0
59             start_res(status, res_headers)
60             return [b"get post info faild"]
61 
62     else:
63         status = "403 method error"
64         start_res(status,res_headers)
65         return [b'method error']
66 
67 # 1、只接受POST请求。数据为json格式,json中标记的,包括但不限于,包括的信息将会入库,其他信息,在告警时会一并发出
68 # {
69 #     "level":"high", #告警级别,"high","medium","info",这个可以在配置文件中配置,配置信息是个列表,有序的从左至右为["high","medium","info"],对应后续告警逻辑及post中json的本字段。
70 #     "@timestamp":"",#告警时间
71 #     "server":"",#告警源,可以是ip,主机名,服务名等可标识的
72 #     "message":""#具体的告警信息
73 # }
74 # 2、根据json中的level自动选择告警途径,选择方式,在配置文件中的alert_method字典信息
75 # 3、将告警内容,存储数据库,便于日后查询
76 # 4、后续提供查询统计告警信息的方法
77 
78 
79 if __name__=="__main__":
80     wsgi_server=make_server(ALERTOR_CONFIG['bind_ip'],ALERTOR_CONFIG['port'],application)
81 
82     wsgi_server.serve_forever()

 

1.3 在一个进度下张开四个线程与在八个进程下展开八个子进程的分别

四、join方法

1.定义:

(1)join方法的效用是阻塞主进度(挡住,不大概施行join今后的说话),潜心施行多进度。

(2)多进度多join的意况下,依次试行各进程的join方法,前头三个停止了才具实行前边一个。

(3)无参数,则等待到该进度结束,才起来推行下贰个进度的join。

 2.代码:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

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=('xiaolan',))
    p2 = Process(target=work,args=('xiaohong',))
    p3 = Process(target=work,args=('xiaolv',))

    p_list = [p1, p2, p3]
    for p in p_list:
        p.start()
    for p in p_list:
        p.join()
    print('主进程')

 

近来此地先这么用,那一个模型的习性是依赖uwsgi运营,2经过,各样进度内4个线程,基准品质是15000伸手总的数量,5000客商端

意气风发、线程概论

1.3.1 哪个人的展开速度越来越快?

from threading import Thread
from multiprocessing import Process
import os

def work():
    print('hello')

if __name__ == '__main__':
    #在主进程下开启线程
    t=Thread(target=work)
    t.start()
    print('主线程/主进程')
    '''
    打印结果:
    hello
    主线程/主进程
    '''

    #在主进程下开启子进程
    t=Process(target=work)
    t.start()
    print('主线程/主进程')
    '''
    打印结果:
    主线程/主进程
    hello
    '''

结论:是因为创造子进度是将主进度完全拷贝风华正茂份,而线程无需,所以线程的成立速度更加快。

五、守护进程

1.定义:

(1)守护进度是主程序成立的。

(2)守护进程会在主进度代码实行完结后就终止。

(3)守护进度内无法再开启子进度,不然抛出十分:

AssertionError: daemonic processes are not allowed to have children。

2.代码:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

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=('xiaolan',))
    p1.daemon = True
    p1.start()
    print('主程序')

 

 ab -n 15000-c 5000 -p test_alert.txt -T application/x-www-form-urlencoded ""

1、何为线程

1.3.2 看看PID的不同

from threading import Thread
from multiprocessing import Process
import os

def work():
    print('hello',os.getpid())

if __name__ == '__main__':
    #part1:在主进程下开启多个线程,每个线程都跟主进程的pid一样
    t1=Thread(target=work)
    t2=Thread(target=work)
    t1.start()
    t2.start()
    print('主线程/主进程pid',os.getpid())

    #part2:开多个进程,每个进程都有不同的pid
    p1=Process(target=work)
    p2=Process(target=work)
    p1.start()
    p2.start()
    print('主线程/主进程pid',os.getpid())


'''
hello 13552
hello 13552
主线程pid: 13552
主线程pid: 13552
hello 1608
hello 6324
'''

总结:可以看来,主进程下开启几个线程,每一种线程的PID都跟主进度的PID相同;而开两个进程,各样进程都有例外的PID。

六、同步锁

1.定义:

平凡被用来贯彻分享能源的共同采访,为每多个分享能源创立三个Lock对象当您须求拜会该财富时,调用qcuqire方法来获得锁对象(假若别的线程已经得到该锁,则当前线程需等待期被保释),待资源访谈完后,在调用release方法释放锁。

2.代码:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

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=('xiaolan',mutex))
    p2 = Process(target=work,args=('xiaohong',mutex))
    p1.start()
    p2.start()
    print('主程序')

 3.代码应用:

仿照抢票进程

python代码:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

import json
import os
import time
from multiprocessing import Process,Lock

def search():
    dic = json.load(open('db.txt'))
    print('33[32m[%s] 看到剩余票数<%s>33[0m' %(os.getpid(),dic['count']))

def get_ticket():
    dic = json.load(open('db.txt'))
    time.sleep(0.5) #模拟读数据库的网络延迟
    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(0.5)  # 模拟写数据库的网络延迟
        json.dump(dic,open('db.txt','w'))
        print('33[31m%s 购票成功33[0m' %os.getpid())

def task(mutex):
    search()
    mutex.acquire()
    get_ticket()
    mutex.release()

if __name__ == '__main__':
    mutex = Lock()
    for i in range(10):
        p = Process(target=task,args=(mutex,))
        p.start()

 db.txt文件:

{"count": 0}

 4.缺点:

(1)运营成效低

(2)供给和谐加章鱼理,操作繁杂

 

意义还集合吧。

各类进度有一个地址空间,何况暗中认可就有三个决定线程。要是把贰个进度比喻为贰个车间的办事经过那么线程正是车间里的多少个叁个流程。

1.3.3 练习

练习一:动用四线程,实现socket 并发连接
服务端:

from threading import Thread
from socket import *
import os

tcpsock = socket(AF_INET,SOCK_STREAM)
tcpsock.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
tcpsock.bind(("127.0.0.1",60000))
tcpsock.listen(5)

def work(conn,addr):
    while True:
        try:
            data = conn.recv(1024)
            print(os.getpid(),addr,data.decode("utf-8"))
            conn.send(data.upper())
        except Exception:
            break

if __name__ == '__main__':
    while True:
        conn,addr = tcpsock.accept()
        t = Thread(target=work,args=(conn,addr))
        t.start()

"""
开启了4个客户端
服务器端输出:
13800 ('127.0.0.1', 63164) asdf
13800 ('127.0.0.1', 63149) asdf
13800 ('127.0.0.1', 63154) adsf
13800 ('127.0.0.1', 63159) asdf

可以看出每个线程的PID都是一样的。
""

客户端:

from socket import *

tcpsock = socket(AF_INET,SOCK_STREAM)
tcpsock.connect(("127.0.0.1",60000))

while True:
    msg = input(">>: ").strip()
    if not msg:continue
    tcpsock.send(msg.encode("utf-8"))
    data = tcpsock.recv(1024)
    print(data.decode("utf-8"))

练习二:有八个任务,三个接受顾客输入,叁个将顾客输入的从头到尾的经过格式化成大写,二个将格式化后的结果存入文件。

from threading import Thread

recv_l = []
format_l = []

def Recv():
    while True:
        inp = input(">>: ").strip()
        if not inp:continue
        recv_l.append(inp)

def Format():
    while True:
        if recv_l:
            res = recv_l.pop()
            format_l.append(res.upper())

def Save(filename):
    while True:
        if format_l:
            with open(filename,"a",encoding="utf-8") as f:
                res = format_l.pop()
                f.write("%sn" %res)

if __name__ == '__main__':
    t1 = Thread(target=Recv)
    t2 = Thread(target=Format)
    t3 = Thread(target=Save,args=("db.txt",))
    t1.start()
    t2.start()
    t3.start()

七、进度队列

1.定义:

(1)Queue([maxsize]):创制分享的历程队列,Queue是多进度安全的行列,能够运用Queue达成多进度之间的多寡传递。

(2)maxsize是队列中允许最大项数,省略则无大小限制。

2.代码:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

from multiprocessing import Queue

q = Queue(3)

q.put('first')
q.put('second')
q.put('third')

print(q.get())
print(q.get())
print(q.get())

 

进度只是用来把财富集中到一齐(进程只是三个财富单位,可能说财富汇聚),而线程才是cpu上的实践单位。

1.3.4 线程的join与setDaemon

与经过的艺术都是类似的,其实multiprocessing模块是模仿threading模块的接口;

from threading import Thread
import time
def sayhi(name):
    time.sleep(2)
    print('%s say hello' %name)

if __name__ == '__main__':
    t=Thread(target=sayhi,args=('egon',))
    t.setDaemon(True) #设置为守护线程,主线程结束,子线程也跟着线束。
    t.start()
    t.join()  #主线程等待子线程运行结束
    print('主线程')
    print(t.is_alive())

八、生产者开销者模型

1.定义:

在职业中,大家恐怕会境遇那样风流罗曼蒂克种意况:有些模块肩负产生多少,那些多少由另一个模块来肩负管理(此处的模块是广义的,能够是类、函数、线程、进度等)。发生多少的模块,就形象地喻为生产者;而管理数据的模块,就叫做开支者。在劳动者与顾客之间在加个缓冲区,大家形象的称呼酒店,生产者肩负往仓库了进商品,而客商担当从饭店里拿商品,这就重新组合了劳动者开支者情势。

2.优点:

(1)解耦。

(2)支持并发。

(3)协理忙闲不均。

3.代码:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

from multiprocessing import Process, JoinableQueue
import time, os

def producer(q, name):
    for i in range(3):
        time.sleep(1)
        res = '%s%s' % (name, i)
        q.put(res)
        print('33[45m<%s> 生产了 [%s]33[0m' % (os.getpid(), res))
    q.join()

def consumer(q):
    while True:
        res = q.get()
        time.sleep(1.5)
        print('33[34m<%s> 吃了 [%s]33[0m' % (os.getpid(), res))
        q.task_done()

if __name__ == '__main__':
    q = JoinableQueue()
    p1 = Process(target=producer, args=(q, '红烧肉'))
    p2 = Process(target=producer, args=(q, '鱼香肉丝'))
    p3 = Process(target=producer, args=(q, '锅包肉'))
    c1 = Process(target=consumer, args=(q,))
    c2 = Process(target=consumer, args=(q,))
    c1.daemon = True
    c2.daemon = True
    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()
    p1.join()
    print('主程序')

 

三十二线程(即三个调控线程)的定义是,在叁个历程中存在四个调整线程,两个调整线程分享该进程的地址空间(资源)

1.3.5 线程相关的其余办法补充

Thread实例对象的秘技:

  • isAlive():再次来到纯种是或不是是活跃的;
  • getName():重回线程名;
  • setName():设置线程名。

threading模块提供的有些方式:

  • threading.currentThread():重回当前的线程变量
  • threading.enumerate():再次来到一个包蕴正在运作的线程的列表。正在周转指线程运行后、截止前,不包蕴运转前和截至后。
  • threading.activeCount():再次回到正在周转的线程数量,与len(threading.enumerate())有风流倜傥致结果。
from threading import Thread
import threading
import os

def work():
    import time
    time.sleep(3)
    print(threading.current_thread().getName())


if __name__ == '__main__':
    #在主进程下开启线程
    t=Thread(target=work)
    t.start()

    print(threading.current_thread().getName()) #获取当前线程名
    print(threading.current_thread()) #主线程
    print(threading.enumerate()) #连同主线程在内有两个运行的线程,返回的是活跃的线程列表
    print(threading.active_count())  #活跃的线程个数
    print('主线程/主进程')

    '''
    打印结果:
    MainThread
    <_MainThread(MainThread, started 140735268892672)>
    [<_MainThread(MainThread, started 140735268892672)>, <Thread(Thread-1, started 123145307557888)>]
    2
    主线程/主进程
    Thread-1
    '''

九、进程池

1.定义:

Pool可以提供钦赐数量的历程供顾客调用,当有新的呼吁提交到pool中时,假设池还尚未满,那么就能创设一个新的进度用来实行该乞求;但即使池中的进度数已经达到规定的标准规定最大值,那么该央浼就能等待,直到池中有进度结束,才会创制新的历程来它。

2.代码:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

from multiprocessing import Pool
import os
import time

def work(n):
    print('task <%s> is runing' % os.getpid())
    time.sleep(2)
    return n**2

if __name__ == '__main__':
    p = Pool(4)
    res_l = []
    for i in range(10):
        res = p.apply_async(work,args=(i,))
        res_l.append(res)
    p.close()
    p.join()

 3.进程池之回调函数:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

import requests
import os,time
from multiprocessing import Pool

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(dic):
    print('<%s> parse :%s' % (os.getpid(), dic['url']))
    time.sleep(0.5)
    res = 'url:%s size:%sn' % (dic['url'], len(dic['text']))
    with open('db.txt', 'a') as f:
        f.write(res)

if __name__ == '__main__':
    p = Pool(4)
    urls = [
        'https://www.baidu.com',
        'https://www.qq.com',
        'https://www.163.com',
        'https://www.sina.com',
        'https://www.jd.com',
        'https://www.taobao.com',
        'https://www.sohu.com',
    ]

    for url in urls:
        p.apply_async(get_page, args=(url,), callback=parse_page)
    p.close()
    p.join()
    print('主进程pid:', os.getpid())

 

创设进度的开支要远高于线程开进程也就是建三个车间,而开线程相当于建一条流水线。

二、 Python GIL

GIL全称Global Interpreter Lock,即全局解释器锁。首先须要分明的有些是GIL并非Python的特色,它是在促成Python分析器(CPython)时所引进的贰个定义。就好比C++是意气风发套语言(语法)标准,可是足以用差别的编写翻译器来编写翻译成可进行代码。盛名的编写翻译器比如GCC,INTEL C++,Visual C++等。Python也一样,同样大器晚成段代码能够通过CPython,PyPy,Psyco等不等的Python试行处境来奉行。像在这之中的JPython就未有GIL。可是因为CPython是绝大好多条件下默许的Python实践遇到。所以在数不完人的定义里CPython正是Python,也就想当然的把GIL归纳为Python语言的短处。所以这里要先明了一点:GIL实际不是Python的特点,Python完全能够不依靠于于GIL

十、paramiko模块

1.定义:

paramiko是用python语言写的三个模块,遵循SSH2公约,帮衬以加密和验证的格局,举办远程服务器的连年。

是因为采纳的是python那样的能够跨平台运维的语言,所以具备python援助的平台,如Linux, Solaris, BSD, MacOS X, Windows等,paramiko都可以援救,因而,倘若急需利用SSH从一个平台连接到别的贰个阳台,实行一密密层层的操作时,paramiko是精品工具之后生可畏。

2.安装:

出于paramiko是第三方模块,所以是亟需我们单独安装的。

pip3 install paramiko

 3.代码:

(1)使用密码连接的方式:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.0.1', port=22, username='root', password='root123456')

stdin, stdout, stderr = ssh.exec_command('df -h')
result = stdout.read()
print(result.decode('utf-8'))
ssh.close()

 (2)使用秘钥连接的法子:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

import paramiko

private_key = paramiko.RSAKey.from_private_key_file('id_rsa')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.0.1', port=22, username='root', pkey=private_key)

stdin, stdout, stderr = ssh.exec_command('df')
result = stdout.read()
print(result.decode('utf-8'))
ssh.close()

 (3)上传或下载文件:

#!/usr/binl/env python
#encoding: utf-8
#author: YangLei

import paramiko

transport = paramiko.Transport(('192.168.0.1', 22))
transport.connect(username='root', password='root123456')

sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put('test.txt', '/tmp/test.txt')
sftp.get('/tmp/test.txt', 'test.txt')
transport.close()

 

2、线程和经过的分别

2.1 什么是全局解释器锁GIL

Python代码的实行由Python 虚拟机(也叫解释器主循环,CPython版本)来调控,Python 在规划之初就思虑到要在解释器的主循环中,同不日常间唯有三个线程在试行,即在任意时刻,唯有多少个线程在解释器中运转。对Python 设想机的访谈由全局解释器锁(GIL)来支配,就是以此锁能保障同不时刻独有叁个线程在运转。
在四线程情形中,Python 设想机按以下办法实施:

  1. 设置GIL
  2. 切换到多少个线程去运行
  3. 运行:
    a. 钦点数量的字节码指令,恐怕
    b. 线程主动让出调节(能够调用time.sleep(0))
  4. 把线程设置为睡眠状态
  5. 解锁GIL
  6. 重复重新以上全部手续

在调用外界代码(如C/C++扩张函数)的时候,GIL 将会被锁定,直到这几个函数甘休截至(由于在这里时期未有Python 的字节码被周转,所以不会做线程切换)。

1.Threads share the address space of the process that created it; processes have their own address space.
2.Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
3.Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
4.New threads are easily created; new processes require duplication of the parent process.
5.Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
6.Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.

2.2 全局解释器锁GIL设计思想与范围

GIL的统一准备简化了CPython的贯彻,使得对象模型,包含主要的内建档案的次序如字典,都以富含可以并发访谈的。锁住全局解释器使得比较简单的实现对三十二线程的支撑,但也损失了多管理器主机的并行总括工夫。
然则,不论标准的,照旧第三方的恢弘模块,都被设计成在实行密集总结任务是,释放GIL。
还会有,正是在做I/O操作时,GIL总是会被放出。对具备面向I/O 的(会调用内建的操作系统C 代码的)程序来讲,GIL 会在这里个I/O 调用早先被放飞,以允许任何的线程在这里个线程等待I/O 的时候运维。假使是纯总括的次第,未有 I/O 操作,解释器会每间距 100 次操作就释放那把锁,让其余线程有机会试行(这一个次数能够因而sys.setcheckinterval 来调度)即便某线程并未选择过多I/O 操作,它会在友好的光阴片内平昔攻陷管理器(和GIL)。也便是说,I/O 密集型的Python 程序比臆想密集型的次第更能丰富利用十二线程际遇的功利。

上边是Python 2.7.9手册中对GIL的简短介绍:
The mechanism used by the CPython interpreter to assure that only one thread executes Python bytecode at a time. This simplifies the CPython implementation by making the object model (including critical built-in types such as dict) implicitly safe against concurrent access. Locking the entire interpreter makes it easier for the interpreter to be multi-threaded, at the expense of much of the parallelism afforded by multi-processor machines.
However, some extension modules, either standard or third-party, are designed so as to release the GIL when doing computationally-intensive tasks such as compression or hashing. Also, the GIL is always released when doing I/O.
Past efforts to create a “free-threaded” interpreter (one which locks shared data at a much finer granularity) have not been successful because performance suffered in the common single-processor case. It is believed that overcoming this performance issue would make the implementation much more complicated and therefore costlier to maintain.

从上文中得以见到,针对GIL的标题做的浩大立异,如利用越来越细粒度的锁机制,在单处理器情形下反而产生了品质的暴跌。普遍认为,克服那特个性难点会变成CPython达成更为目不暇接,由此维护费用越来越昂扬。

中译:

三、 Python多进程与多线程相比

有了GIL的留存,同偶尔刻同活龙活现进度中唯有一个线程被施行?这里只怕人有二个疑云:多进度能够采纳多核,可是付出大,而Python三十二线程开支小,但并非常的小概使用多核的优势?要消除那个标题,我们必要在以下几点上实现共鸣:

  • CPU是用来计量的!
  • 多核CPU,意味着能够有多少个核并行达成总结,所以多核进级的是测算质量;
  • 各样CPU大器晚成旦遇见I/O阻塞,依然须要等待,所以多核对I/O操作没什么用处。

理当如此,对于二个程序来讲,不会是纯总计依旧纯I/O,大家只可以相对的去看贰个顺序到底是精打细算密集型,依然I/O密集型。进而越来越深入分析Python的八线程有英雄无发挥专长。

分析:

小编们有多个职分急需管理,管理访求肯定是要有出现的职能,施工方案能够是:

  • 方案如火如荼:开启多少个经过;
  • 方案二:一个经过下,开启三个经过。

单核情形下,解析结果:

  • 即便八个职务是总计密集型,未有多核来并行总括,方案意气风发徒增了创立进程的支付,方案二胜;
  • 若果八个职分是I/O密集型,方案风度翩翩制程的费用大,且经过的切换速度远不比线程,方案二胜。

多核景况下,深入分析结果:

  • 假定八个职分是密集型,多核意味着并行 计算,在python中一个历程中平等时刻唯有多少个线程试行用不上多核,方案一胜;
  • 后生可畏旦多个职务是I/O密集型,再多的核 也消除不了I/O难题,方案二胜。

结论:现今的Computer基本上都以多核,python对于计算密集型的天职开多线程的频率并无法推动多大质量上的晋升,以至比不上串行(没有大气切换),可是,对于I/O密集型的天职作用如故有生硬进步的。

代码达成相比

算算密集型:

#计算密集型
from threading import Thread
from multiprocessing import Process
import os
import time
def work():
    res=0
    for i in range(1000000):
        res+=i

if __name__ == '__main__':
    t_l=[]
    start_time=time.time()
    for i in range(100):
        # t=Thread(target=work) #我的机器4核cpu,多线程大概15秒
        t=Process(target=work) #我的机器4核cpu,多进程大概10秒
        t_l.append(t)
        t.start()

    for i in t_l:
        i.join()
    stop_time=time.time()
    print('run time is %s' %(stop_time-start_time))
    print('主线程')

I/O密集型:

#I/O密集型
from threading import Thread
from multiprocessing import Process
import time
import os
def work():
    time.sleep(2) #模拟I/O操作,可以打开一个文件来测试I/O,与sleep是一个效果
    print(os.getpid())

if __name__ == '__main__':
    t_l=[]
    start_time=time.time()
    for i in range(500):
        # t=Thread(target=work) #run time is 2.195
        t=Process(target=work) #耗时大概为37秒,创建进程的开销远高于线程,而且对于I/O密集型,多cpu根本不管用
        t_l.append(t)
        t.start()

    for t in t_l:
        t.join()
    stop_time=time.time()
    print('run time is %s' %(stop_time-start_time))

总结:
行使场景:
二十四线程用于I/O密集型,如socket、爬虫、web
多进度用于总计密集型,如金融分析

1、线程共享创建它的进程的地址空间;进程有自己的地址空间。
2、线程可以直接访问其进程的数据段;进程有它们自己的父进程数据段的副本。
3、线程可以直接与进程的其他线程通信;进程必须使用进程间通信来与兄弟进程通信。
4、新线程很容易创建;新进程需要复制父进程。
5、线程可以对同一进程的线程进行相当大的控制;进程只能对子进程执行控制。
6、对主线程的更改(取消、优先级更改等)可能会影响该进程的其他线程的行为;对父进程的更改不会影响子进程。

四、锁

3、二十四线程的亮点

4.1 同步锁

急需:对多个全局变量,开启玖十九个线程,每一个线程都对该全局变量做减1操作;

不加锁,代码如下:

import time
import threading

num = 100  #设定一个共享变量
def addNum():
    global num #在每个线程中都获取这个全局变量
    #num-=1

    temp=num
    time.sleep(0.1)
    num =temp-1  # 对此公共变量进行-1操作

thread_list = []

for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list: #等待所有线程执行完毕
    t.join()

print('Result: ', num)

分析:上述程序开启100线程并不能够把全局变量num减为0,第贰个线程实践addNum境遇I/O阻塞后高速切换成下一个线程施行addNum,由于CPU实施切换的进程相当的慢,在0.1秒内就切换实现了,那就招致了第二个线程在获得num变量后,在time.sleep(0.1)时,其余的线程也都得到了num变量,全体线程获得的num值皆以100,所以最后减1操作后,正是99。加锁完毕。

加锁,代码如下:

import time
import threading

num = 100   #设定一个共享变量
def addNum():
    with lock:
        global num
        temp = num
        time.sleep(0.1)
        num = temp-1    #对此公共变量进行-1操作

thread_list = []

if __name__ == '__main__':
    lock = threading.Lock()   #由于同一个进程内的线程共享此进程的资源,所以不需要给每个线程传这把锁就可以直接用。
    for i in range(100):
        t = threading.Thread(target=addNum)
        t.start()
        thread_list.append(t)

    for t in thread_list:  #等待所有线程执行完毕
        t.join()

    print("result: ",num)

加锁后,第三个线程得到锁后最早操作,第一个线程必需等待第贰个线程操作达成后将锁释放后,再与别的线程竞争锁,获得锁的线程才有权操作。这样就保持了数据的安全,可是拖慢了推行进程。
注意:with locklock.acquire()(加锁)与lock.release()(释放锁)的简写。

import threading

R=threading.Lock()

R.acquire()
'''
对公共数据的操作
'''
R.release()

二十多线程和多进度一样指的是,在三个进度中开启七个线程

GIL vs Lock

机智的同学可能会问到这个问题,就是既然你之前说过了,Python已经有一个GIL来保证同一时间只能有一个线程来执行了,为什么这里还需要lock? 

首先大家供给达到共鸣:锁的目标是为着保险分享的数额,同时只能有一个线程来修改分享的多少

然后,我们能够得出结论:爱慕差别的数目就活该加差别的锁。

末段,难点就很晴朗了,GIL 与Lock是两把锁,珍视的数量不平等,后者是解释器级别的(当然维护的就是解释器品级的数码,比方垃圾回收的数码),前面一个是爱惜客户自个儿支付的应用程序的多少,很明白GIL不肩负那事,只好客户自定义加章鱼理,即Lock

详细的:

因为Python解释器帮你活动按时开展内部存款和储蓄器回收,你可见为python解释器里有三个独立的线程,每过风姿洒脱段时间它起wake up做一次全局轮询看看哪些内部存款和储蓄器数据是能够被清空的,此时你和睦的主次 里的线程和 py解释器本身的线程是并发运转的,要是你的线程删除了三个变量,py解释器的废料回收线程在清空这几个变量的经过中的clearing时刻,大概三个其余线程正好又重新给这些还没来及得清空的内部存款和储蓄器空间赋值了,结果就有一点都不小概率新赋值的多少被去除了,为了解决类似的问题,python解释器轻便无情的加了锁,即当二个线程运维时,别的人都不可能动,那样就一挥而就了上述的标题, 那能够说是Python开始时期版本的遗留难题。

1)四线程分享一个进程的地方空间(财富)

4.2 死锁与递归锁

所谓死锁:是指三个或五个以上的历程或线程在实行进度中,因争夺能源而招致的如日方升种相互等待的风貌,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态,或类别发生了死锁。那此永恒在相互等待的历程称死锁进度

正如代码,就能够发出死锁:

from threading import Thread,Lock
import time
mutexA=Lock()
mutexB=Lock()

class MyThread(Thread):
    def run(self):
        self.func1()
        self.func2()
    def func1(self):
        mutexA.acquire()
        print('33[41m%s 拿到A锁33[0m' %self.name)

        mutexB.acquire()
        print('33[42m%s 拿到B锁33[0m' %self.name)
        mutexB.release()

        mutexA.release()

    def func2(self):
        mutexB.acquire()
        print('33[43m%s 拿到B锁33[0m' %self.name)
        time.sleep(2)

        mutexA.acquire()
        print('33[44m%s 拿到A锁33[0m' %self.name)
        mutexA.release()

        mutexB.release()

if __name__ == '__main__':
    for i in range(10):
        t=MyThread()
        t.start()

'''
Thread-1 拿到A锁
Thread-1 拿到B锁
Thread-1 拿到B锁
Thread-2 拿到A锁
然后就卡住,死锁了
'''

消除死锁的主意

制止发出死锁的议程正是用递归锁,在python中为了扶持在同一线程中数10次伸手同一财富,python提供了可重入锁RLock

这个RLock内部维护着二个Lock和七个counter变量,counter记录了acquire(得到锁)的次数,进而使得资源得以被反复require。直到四个线程全部的acquire都被release(释放)后,别的的线程才干获得能源。上面的例证假如利用RLock代替Lock,就不会时有发生死锁的光景了。

mutexA=mutexB=threading.RLock() #二个线程得到锁,counter加1,该线程内又赶过加锁的情状,则counter继续加1,那之间具备别的线程都只好等待,等待该线程释放拥有锁,即counter依次减少到0结束。

2) 线程比进程更轻量级,线程比进度更便于创制可收回,在不少操作系统中,创设壹个线程比创设贰个经过要快10-100倍,在有恢宏线程要求动态和便捷修改时,那黄金时代个性很有用

4.3 信号量Semaphore

同进度的实信号量同样。
用一个无聊的事例来讲,锁也正是独立卫生间,唯有三个坑,同不日常刻只好有一人拿走锁,进去使用;而实信号量相当于集体茶水间,举个例子有5个坑,同不常刻能够有5个人获得锁,并使用。

Semaphore治本一个放到的计数器,每当调用acquire()时,内置计数器-1;调用release()时,内置计数器+1;计数器不能够小于0,当计数器为0时,acquire()将封堵线程,直到其余线程调用release()

实例:
再者唯有5个线程能够收获Semaphore,即能够界定最瓜达拉哈拉接数为5:

import threading
import time

sem = threading.Semaphore(5)
def func():
    if sem.acquire():   #也可以用with进行上下文管理
        print(threading.current_thread().getName()+"get semaphore")
        time.sleep(2)
        sem.release()

for i in range(20):
    t1 = threading.Thread(target=func)
    t1.start()

利用with拓宽上下文物管理理:

import threading
import time

sem = threading.Semaphore(5)

def func():
    with sem:   
        print(threading.current_thread().getName()+"get semaphore")
        time.sleep(2)

for i in range(20):
    t1 = threading.Thread(target=func)
    t1.start()

注:能量信号量与进度池是全然分裂大器晚成的定义,进度池Pool(4)最大不得不发出4个进度,而且从头至尾都只是这4个进度,不会发出新的,而非连续信号量是发生一群线程/进度。

3) 若八个线程都以cpu密集型的,那么并无法收获属性上的增进,可是只要存在大批量的测算和大量的I/O管理,具有八个线程允许那些活动互动肥胖运转,进而会加速程序实施的速度。

4.4 事件Event

同进程的如出意气风发辙

线程的贰个主要天性是各类线程都以单身运行且状态不行预测。如若程序中的别的线程通过判别某些线程的事态来明确本身下一步的操作,那时线程同步难点就能够变得不得了难办,为了消除那些标题大家应用threading库中的Event对象。

Event指标包蕴一个可由线程设置的确定性信号标记,它同意线程等待有些事件的发出。在初叶景况下,伊芙nt对象中的信号标识被安装为假。如若有线程等待贰个伊夫nt对象,而以此Event对象的阐明为假,那么这几个线程将会被 一贯不通直至该 标记为真。二个线程若是将二个Event对象的非复信号标识设置为真,它将唤起全部等待那些伊芙nt对象的线程。要是三个线程等待二个已经被 设置 为实在Event对象,那么它将忽视这几个事件,继续施行。

伊芙nt对象具备部分方法:
event = threading.Event() #产生叁个事变目的

  • event.isSet():返回event状态值;
  • event.wait():如果event.isSet() == False,将卡住线程;
  • event.set():设置event的动静值为True,全数阻塞池的线程步入就绪状态,等待操作系统高度;
  • event.clear():复苏event的图景值False。

选择场景:

比方说,大家有七个线程须求一连数据库,我们想要在运转时确认保证Mysql服务寻常,才让这些专门的职业线程去老是Mysql服务器,那么我们就足以利用threading.Event()编写制定来和谐种种职业线程的连年操作,主线程中会去尝尝连接Mysql服务,若是符合规律的话,触发事件,各工作线程会尝试连接Mysql服务。

from threading import Thread,Event
import threading
import time,random
def conn_mysql():
    print('33[42m%s 等待连接mysql。。。33[0m' %threading.current_thread().getName())
    event.wait()  #默认event状态为False,等待
    print('33[42mMysql初始化成功,%s开始连接。。。33[0m' %threading.current_thread().getName())


def check_mysql():
    print('33[41m正在检查mysql。。。33[0m')
    time.sleep(random.randint(1,3))
    event.set()   #设置event状态为True
    time.sleep(random.randint(1,3))

if __name__ == '__main__':
    event=Event()
    t1=Thread(target=conn_mysql) #等待连接mysql
    t2=Thread(target=conn_mysql) #等待连接myqsl
    t3=Thread(target=check_mysql) #检查mysql

    t1.start()
    t2.start()
    t3.start()


'''
输出如下:
Thread-1 等待连接mysql。。。
Thread-2 等待连接mysql。。。
正在检查mysql。。。
Mysql初始化成功,Thread-1开始连接。。。
Mysql初始化成功,Thread-2开始连接。。。
'''

注:threading.Eventwait方法仍然是还不错一个过期参数,暗中认可情形下,假若事件向来未曾发生,wait方法会一向不通下去,而参加这些超时参数之后,借使打断时间当先那个参数设定的值之后,wait方法会重回。对应于上边的使用场景,就算mysql服务器平素未曾运转,大家盼望子线程能够打字与印刷一些日志来不断提示大家日前并未有一个方可络绎不绝的mysql服务,大家就可以安装这几个超时参数来达到那样的指标:

上例代码修改后如下:

from threading import Thread,Event
import threading
import time,random
def conn_mysql():
    count = 1
    while not event.is_set():
        print("33[42m%s 第 <%s> 次尝试连接。。。"%(threading.current_thread().getName(),count))
        event.wait(0.2)
        count+=1
    print("33[45mMysql初始化成功,%s 开始连接。。。33[0m"%(threading.current_thread().getName()))

def check_mysql():
    print('33[41m正在检查mysql。。。33[0m')
    time.sleep(random.randint(1,3))
    event.set()
    time.sleep(random.randint(1,3))

if __name__ == '__main__':
    event=Event()
    t1=Thread(target=conn_mysql) #等待连接mysql
    t2=Thread(target=conn_mysql) #等待连接mysql
    t3=Thread(target=check_mysql) #检查mysql

    t1.start()
    t2.start()
    t3.start()

那般,我们就足以在等候Mysql服务运转的同一时间,见到工作线程少保在守候的情状。应用:连接池。

4) 在多cpu系统中,为了最大限度的利用多核,能够拉开多少个线程,比开进程开销要小的多。(这一条并不适用于python)

4.5 定时器timer

电磁打点计时器,钦赐n秒后推行某操作。

from threading import Timer

def hello():
    print("hello, world")

t = Timer(1, hello)  #1秒后执行任务hello
t.start()   # after 1 seconds, "hello, world" will be printed

4.6 线程队列queue

queue队列:使用import queue,用法与经过Queue一样。

queue下有三种队列:

  • queue.Queue(maxsize) 先进先出,先放进队列的多寡,先被抽出来;
  • queue.LifoQueue(maxsize) 后进先出,(Lifo 意为last in first out),后放进队列的数码,先被抽取来
  • queue.PriorityQueue(maxsize) 优先级队列,优先级越高优先抽取来。

举例:
先进先出:

import queue

q=queue.Queue()
q.put('first')
q.put('second')
q.put('third')

print(q.get())
print(q.get())
print(q.get())
'''
结果(先进先出):
first
second
third
'''

后进先出:

import queue

q=queue.LifoQueue()
q.put('first')
q.put('second')
q.put('third')

print(q.get())
print(q.get())
print(q.get())
'''
结果(后进先出):
third
second
first
'''

先行级队列:

import queue

q=queue.PriorityQueue()
#put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
q.put((20,'a'))
q.put((10,'b'))
q.put((30,'c'))

print(q.get())
print(q.get())
print(q.get())
'''
结果(数字越小优先级越高,优先级高的优先出队):
(10, 'b')
(20, 'a')
(30, 'c')
'''

 

五、协程

协程:是单线程下的产出,又称微线程、纤程,葡萄牙语名:Coroutine协程是风姿罗曼蒂克种顾客态的轻量级线程,协程是由客商程序自个儿说了算调解的。

亟需重申的是:

1. python的线程属于基本级其他,即由操作系统调控调节(如单线程朝气蓬勃旦相遇io就被迫交出cpu施行权限,切换其余线程运转)

  1. 单线程内展开协程,生龙活虎旦相遇io,从应用程序品级(而非操作系统)调节切换

相对来说操作系统调整线程的切换,顾客在单线程内决定协程的切换,优点如下:

1. 协程的切换开支更加小,属于程序级其他切换,操作系统完全感知不到,由此尤其轻量级

  1. 单线程内就足以兑现产出的效果,最大限度地利用cpu。

要兑现协程,关键在于客商程序自个儿主宰程序切换,切换早先必需由客户程序自身保留协程上三次调用时的景色,如此,每回重复调用时,能够从上次的地点继续实践

(详细的:协程具备本身的贮存器上下文和栈。协程调整切换时,将存放器上下文和栈保存到任何地方,在切回到的时候,复苏原先封存的存放器上下文和栈)

TAG标签:
版权声明:本文由必威发布于必威-操作系统,转载请注明出处:UDP是无连接不可靠的数据报协议必威:,为了能