Python_oldboy_自動化運維之路_線程,進程,協程(十一)

本節內容:html

  1. 線程
  2. 進程
  3. 協程
  4. IO多路複用
  5. 自定義異步非阻塞的框架

線程和進程的介紹python

舉個例子,拿甄嬛傳舉列線程和進程的關係:linux

總結:
1.工做最小單元是線程,進程說白了就是提供資源的程序員

2.一個應用程序至少有一個進程,一個進程裏至少有一個線程web

3.應用場景:io密集型適合用多線程,計算密集型(cpu)適合用多進程windows

4.GIL:全局解釋器鎖,做用:保證同一個進程中只能有一個線程同時被調用服務器

5.python的一個詬病:前提是被cpu調度,由於有GIL,一個應用只有一個進程,縱容有多個線程,也體現不出多核的優點,除非有多個進程,好處是下降的python開發者的難度。多線程

1.線程

Threading用於提供線程相關的操做,線程是應用程序中工做的最小單元,開線程的主要的做用是能夠幫咱們同時作某些事情。併發

線程的基本使用:app

1.線程的基本使用

# -*- coding: UTF-8 -*-
#blog:http://www.cnblogs.com/linux-chenyang/
import threading
import time

def task(arg):                                      #隔1s後執行這三十個線程,是併發的,同時工做
    time.sleep(1)
    print('aaaaaaa',arg)


for i in range(30):                                 #這個是建立出30個線程來
    t = threading.Thread(target=task,args=[i,])
#    t.setDaemon(True)     #主程序結束,不等待子線程
#    t.setDaemon(False)   #默認

    t.start()

#    t.join()    #等一個線程執行完在執行下一個線程
#    t.join(1)  #等待最大時間,最多等1秒

print('end')    #這個就至關於主線程
線程
#end是主線程,等主線程建立好後會隔1s併發執行30個函數
end
aaaaaaa 0
aaaaaaa 1
aaaaaaa 2
aaaaaaa 4
aaaaaaa 5
aaaaaaa 3
aaaaaaa 6
aaaaaaa 7
aaaaaaa 9
aaaaaaa 8
aaaaaaa 11
aaaaaaa 10
aaaaaaa 13
aaaaaaa 12
aaaaaaa 14
aaaaaaa 17
aaaaaaa 15
aaaaaaa 16
aaaaaaa 19
aaaaaaa 18
aaaaaaa 20
aaaaaaa 21
aaaaaaa 22
aaaaaaa 23
aaaaaaa 25
aaaaaaa 26
aaaaaaa 24
aaaaaaa 27
aaaaaaa 28
aaaaaaa 29
輸出

2.線程任務被調用過程

#線程執行的過程,自定義線程,咱們的函數是被run方法調用的
import threading
import time

class MyThread(threading.Thread):
    def __init__(self,func,*args,**kwargs):
        super(MyThread,self).__init__(*args,**kwargs)
        self.func = func

    def run(self):
        self.func()
        print('-------首先執行的是run方法-----')

def task():
    print('task函數。。。。')


obj=MyThread(func=task)
obj.start()
線程
task函數。。。。
-------首先執行的是run方法-----
輸出

線程鎖:

3.線程鎖,只能有一我的使用鎖

#用處:這樣的話變量v就是來一個減一個,不會出現假如其中有線程沒有執行完,在去減就會出錯

import threading
import time

#建立鎖
lock = threading.Lock()
#lock = threading.RLock()   #使用這種方法能夠鎖屢次,可是解鎖也要解鎖屢次,帶遞歸的鎖

v=10

def task(arg):
    time.sleep(2)

    #申請使用鎖,其餘人等
    lock.acquire()
    #lock.acquire()

    global v
    v -= 1
    print(v)

    #釋放
    lock.release()
    #lock.release()

for i in range(10):
    t = threading.Thread(target=task,args=(i,))  #元組的方式最好加逗號,(後續)怕誤覺得是個函數
    t.start()
線程鎖
9
8
7
6
5
4
3
2
1
0
輸出

4.線程鎖,同時多我的使用鎖

import threading
import time

#建立鎖
lock = threading.BoundedSemaphore(3)      #同時鎖三個線程

v=10

def task(arg):

    lock.acquire()

    time.sleep(1)                        #當進來鎖後等1秒,這時顯示打印會三條三條的顯示。
    global v
    v -= 1
    print(v)

    lock.release()


for i in range(10):
    t = threading.Thread(target=task,args=(i,))  #元組的方式最好加逗號,(後續)怕誤覺得是個函數
    t.start()
線程鎖
#三個三個顯示,等1秒
9
8
7
6
5
4
3
2
1
0
輸出

5.線程鎖,事件鎖的應用

#3.事件鎖,當觸發某個條件,我生成的子線程才工做
import threading
import time

#建立鎖
lock = threading.Event()

def task(arg):

    time.sleep(1)
    #鎖住全部的線程
    lock.wait()
    print(arg)

for i in range(10):
    t = threading.Thread(target=task,args=(i,))
    t.start()

while True:
    value = input('>>')
    if value == '1':
        lock.set()
#        lock.clear()   默認
事件鎖
>>1
>>0
2
4
6
8
1
3
5
7
9
輸出

6.線程鎖,條件condition用法

#4.條件,Condition的用法,輸入幾就釋放幾個線程
import threading
import time

#建立鎖
lock = threading.Condition()

def task(arg):

    time.sleep(1)
    #鎖住全部的線程
    lock.acquire()
    lock.wait()
    print('線程',arg)
    lock.release()

for i in range(10):
    t = threading.Thread(target=task,args=(i,))
    t.start()

while True:
    value = input('>>')
    lock.acquire()
    lock.notify(int(value))
    lock.release()
線程鎖
C:\Python35\python3.exe D:/pycharm/s16/day9/2.鎖.py
>>2
>>線程 0
線程 2
3
>>線程 1
線程 4
線程 3
輸出

 線程池(先建立鏈接,在去執行):1.最基本的使用,線程池,如有100個任務,個人線程池總共有5個線程,每一個線程處理完任務會繼續處理下一個任務。

# -*- coding: UTF-8 -*-
#blog:http://www.cnblogs.com/linux-chenyang/
from concurrent.futures import ThreadPoolExecutor
import time

def task(arg):
    time.sleep(1)
    print('線程池',arg)

pool = ThreadPoolExecutor(5)

for i in range(100):
    #去鏈接池中取鏈接
    pool.submit(task,i)
線程池
#任務會5個5個來,每隔1秒
C:\Python35\python3.exe D:/pycharm/s16/day9/3.線程鏈接池.py
線程池 0
線程池 2
線程池 1
線程池 3
線程池 4
線程池 5
線程池 6
線程池 7
線程池 8
線程池 9
線程池 10
線程池 11
線程池 13
線程池 12
線程池 14
線程池 15
線程池 18
線程池 16
線程池 17
線程池 19
線程池 20
線程池 21
線程池 22
線程池 23
線程池 24
線程池 25
線程池 26
線程池 27
線程池 28
線程池 29
線程池 30
線程池 32
線程池 34
線程池 31
線程池 33
線程池 35
線程池 36
線程池 37
線程池 38
線程池 39
線程池 40
線程池 41
線程池 42
線程池 44
線程池 43
線程池 45
線程池 46
線程池 47
線程池 48
線程池 49
線程池 50
線程池 51
線程池 52
線程池 53
線程池 54
線程池 55
線程池 56
線程池 57
線程池 58
線程池 59
線程池 60
線程池 61
線程池 62
線程池 63
線程池 64
線程池 65
線程池 66
線程池 67
線程池 68
線程池 69
線程池 70
線程池 71
線程池 72
線程池 74
線程池 73
線程池 75
線程池 76
線程池 77
線程池 79
線程池 78
線程池 80
線程池 81
線程池 82
線程池 84
線程池 83
線程池 85
線程池 87
線程池 86
線程池 88
線程池 89
線程池 91
線程池 90
線程池 92
線程池 93
線程池 94
線程池 95
線程池 96
線程池 97
線程池 98
線程池 99
輸出

2.併發發送http請求,獲取結果

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time
# pip3 install requests
import requests

# ########## 1. 併發發送Http請求,獲取結果 ##########

def task(url):
    response = requests.get(url)
    print('獲得結果:',url,len(response.content))
    # ....

pool = ThreadPoolExecutor(2)
url_list = [
    'http://www.oldboyedu.com',
    'http://www.autohome.com.cn',
    'http://www.baidu.com',
]
for url in url_list:
    print('開始請求',url)
    # 去鏈接池中獲取連接
    pool.submit(task,url)
線程池

3.鏈接池能夠併發去登錄多臺主機,去執行命令。

from concurrent.futures import ThreadPoolExecutor
import time
# pip3 install requests
import requests

def task(host):
    import paramiko
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(hostname=host, port=22, username='wupeiqi', password='123')
    stdin, stdout, stderr = ssh.exec_command('df')
    result = stdout.read()
    ssh.close()
    print(result)

pool = ThreadPoolExecutor(2)
host_list = [
    'c1.com',
    'c2.com',
    'c3.com',
]
for host in host_list:
    print('開始請求',host)
    # 去鏈接池中獲取連接
    pool.submit(task,host)
線程鎖

建立線程池的思惟:若要自定義線程池,線程池裏面的線程默認是沒有啓動線程的,來一個任務起一個線程,來第二個任務先看下第一個線程空閒不空閒,要是不空閒在起第二個線程,以此類推,直到達到最大線程數的值。

4.回調函數

#線程池之分佈式執行,回調執行
#假如我拿到了各個網站的內容,有的人把內容存到本地,有的人把內容上次到網盤
#咱們利用線程池只把數據的結果拿到,至於用戶怎麼操做,那就讓他本身寫個方法(函數)

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import requests

#我本身的方法
def text(future):
    download_response = future.result()                #6.若要拿到response的內容,就執行future.result()語法
    print('我本身的保存數據的方法。。。。',download_response.url,download_response.status_code)


def download(url):                                     #4.下載網頁的方法
    response = requests.get(url)
#    print('獲得結果:',url,len(response.content))
    return response    #response包含了下載的全部內容


pool = ThreadPoolExecutor(2)                           #1.先有個線程池

                                                       #2.有個各個網站的列表
url_list = [
    'http://www.oldboyedu.com',
    'http://www.autohome.com.cn',
    'http://www.baidu.com',
]
for url in url_list:
    print('開始請求',url)
    # 去鏈接池中獲取連接
    future=pool.submit(download,url)                  #3.用線程下載網站的內容

    #這就是回調函數:執行完後在調用一個函數
    future.add_done_callback(text)                    #5.獲取到網站內容後執行text的方法
回調函數
開始請求 http://www.oldboyedu.com
開始請求 http://www.autohome.com.cn
開始請求 http://www.baidu.com
我本身的保存數據的方法。。。。 http://www.oldboyedu.com/ 200
我本身的保存數據的方法。。。。 http://www.baidu.com/ 200
我本身的保存數據的方法。。。。 http://www.autohome.com.cn/beijing/ 200
輸出

5.回調函數優化,把線程和回調函數寫成一個公共的模塊,用戶傳人網站內容和方法

# -*- coding: UTF-8 -*-
#blog:http://www.cnblogs.com/linux-chenyang/
from concurrent.futures import ThreadPoolExecutor
import requests


def download(url):
    response = requests.get(url)
    return response  #response包含了下載網站的全部內容


# url_list = [
#     {'url':'http://www.oldboyedu.com','call':'f1'},
#     {'url':'http://www.autohome.com.cn','call':'f1'},
#     {'url':'http://www.baidu.com','call':'f1'},
# ]

def run(url_list):
    pool = ThreadPoolExecutor(2)
    for item in url_list:
        url = item['url']
        call = item['call']

        future=pool.submit(download,url)
        future.add_done_callback(call)
nb_thread
# -*- coding: UTF-8 -*-
#blog:http://www.cnblogs.com/linux-chenyang/

import nb_thread

def f1(future):
    response =  future.result()
    print(response.text)                   #網站的內容以文本的格式顯示

def f2(future):
    response =  future.result()

def f3(future):
    response =  future.result()


url_list = [
    {'url':'http://www.oldboyedu.com','call':f1},
    {'url':'http://www.autohome.com.cn','call':f2},
    {'url':'http://www.baidu.com','call':f3},
]

nb_thread.run(url_list)
用戶

2.進程

線程和線程之間資源是共享的,進程和進程之間的資源是不共享的。

進程的基本使用:

 1.進程和線程的套路插很少

# -*- coding: UTF-8 -*-
#blog:http://www.cnblogs.com/linux-chenyang/

from multiprocessing import Process
import time

def task(arg):
    time.sleep(2)
    print(arg)

if __name__ == '__main__':                  #windows上必須這麼寫,linux和mac上不用
    for i in range(10):
        p = Process(target=task,args=(i,))
#        p.daemon=True   #主進程不等子進程執行完
        p.start()
#        p.join(1)       #主進程最多等1秒
    print('主進程中的主線程執行到最後。。。。。')
進程
主進程中的主線程執行到最後。。。。。
1
2
0
3
5
7
4
6
8
9
輸出

2.進程的數據是不共享的,驗證以下,和線程作對比

#2.驗證進程數據不共享
#查看進程輸出,每次只有一個數據,不會記錄上次的數據
from  multiprocessing import Process

def task(num,li):
    li.append(num)
    print(li)

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

#利用線程,會記錄上次的數據
# import threading
#
# def task(num,li):
#     li.append(num)
#     print(li)
#
# if __name__ == '__main__':
#     v=[]
#     for i in range(10):
#         p = threading.Thread(target=task,args=(i,v))
#         p.start()
進程數據不共享
C:\Python35\python3.exe D:/pycharm/s16/day9/進程的基本使用.py
[1]
[4]
[0]
[3]
[8]
[9]
[2]
[7]
[6]
[5]
輸出

3.進程之間實現共享數據的兩種方法(備註:第二種方法不加join會報錯,請忽略,緣由爲沒有關閉鏈接,因此加join不會報錯)

特殊的東西
             - Array(‘類型’,長度)
             - Manager().list() / Manager().dict()

# -*- coding: UTF-8 -*-
#blog:http://www.cnblogs.com/linux-chenyang/
#實現進程之間的共享
# #方法一:基於c語言
# from multiprocessing import  Process,Array
#
# def task(num,li):
#     li[num]=1
#     print(list(li))
#
# if __name__ == '__main__':
#     v = Array('i',10)         #i是數據類型(數字),10表示長度,在c語言中列表必須制定數據類型和長度大小,不像python
# #    print(v)       [0,0,0,0,0,0,0,0,0]
#     for i in range(10):
#         p = Process(target=task,args=(i,v,))
#         p.start()
#輸出:
# [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# [1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
# [1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
# [1, 1, 1, 0, 0, 1, 0, 0, 0, 0]
# [1, 1, 1, 0, 0, 1, 0, 0, 0, 1]
# [1, 1, 1, 0, 0, 1, 0, 0, 1, 1]
# [1, 1, 1, 0, 0, 1, 1, 0, 1, 1]
# [1, 1, 1, 1, 0, 1, 1, 0, 1, 1]
# [1, 1, 1, 1, 0, 1, 1, 1, 1, 1]
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

#方法二:基於socket實現的
from multiprocessing import  Process,Manager
def task(num,li):
    li.append(num)
    print(li)

if __name__ == '__main__':
    v = Manager().list()         #表示特殊的列表,能夠共享
    for i in range(10):
        p = Process(target=task,args=(i,v,))
        p.start()
        p.join(1)
進程共享
C:\Python35\python3.exe D:/pycharm/s16/day9/5.進程之間的數據共享.py
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
輸出

4.進程池,和線程池同樣

# -*- coding: UTF-8 -*-
#blog:http://www.cnblogs.com/linux-chenyang/
from concurrent.futures import ProcessPoolExecutor


def call(arg):
    data = arg.result()
    print(data)

def task(arg):
    print(arg)
    return arg+100

if __name__ == '__main__':
    pool = ProcessPoolExecutor(5)
    for i in range(10):
        obj=pool.submit(task,i)
        obj.add_done_callback(call)
線程池

3.協程

線程和進程的操做是由程序觸發系統接口,最後的執行者是系統;協程的操做則是程序員。

協程存在的意義:對於多線程應用,CPU經過切片的方式來切換線程間的執行,線程切換時須要耗時(保存狀態,下次繼續)。協程,則只使用一個線程,在一個線程中規定某個代碼塊執行順序。

協程的適用場景:當程序中存在大量不須要CPU的操做時(IO),適用於協程;

協程永遠是一個線程在執行,對線程的一個分片處理,目的是充分利用線程的資源,單獨拿出來用沒啥做用,只有遇到IO纔會有用greenlet:

# -*- coding: UTF-8 -*-
#blog:http://www.cnblogs.com/linux-chenyang/
#greenlet模塊須要先下載pip3 install greenlet
from greenlet import greenlet

def test1():
    print(12)
    gr2.switch()
    print(34)
    gr2.switch()


def test2():
    print(56)
    gr1.switch()
    print(78)


gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
greenlet(協程)
C:\Python35\python3.exe D:/pycharm/s16/day9/7.協程.py
12
56
34
78
輸出

gevent:

根據協程二次開發:IO+線程,實現一個線程分片處理多個任務,充分利用資源

#根據協程二次開發:IO+線程,實現一個線程分片處理多個任務,充分利用資源
#gevent須要下載
from gevent import monkey; monkey.patch_all()
import gevent
import requests

def f(url):
    response = requests.get(url)
    print(response.url,response.status_code)

gevent.joinall([
        gevent.spawn(f, 'http://www.qq.com/'),
        gevent.spawn(f, 'http://www.oldboyedu.com/'),
        gevent.spawn(f, 'http://www.baidu.com/'),
])
IO+線程(基於greenletl)
C:\Python35\python3.exe D:/pycharm/s16/day9/7.協程.py
http://www.baidu.com/ 200
http://www.oldboyedu.com/ 200
http://www.qq.com/ 200
輸出

4.IO多路複用

http://www.cnblogs.com/wupeiqi/articles/5040823.html

一個線程作到了同時監聽多個端口發來的請求,僞造了一種併發的概念,因此的web框架都是基於如下代碼演變過來的

1.io多路複用(能夠監聽多個socket對象)

import socket
import select

# IO多路複用:8002,8001
#

sk1 = socket.socket()
sk1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
sk1.bind(('127.0.0.1',8003,))
sk1.listen(5)

sk2 = socket.socket()
sk2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
sk2.bind(('127.0.0.1',8004,))
sk2.listen(5)
inputs = [sk1,sk2,]
while True:
    # IO多路複用,同時監聽多個socket對象
    #    - select,內部進行循環操做(1024)  在系統底層主動查看有沒有人給我發來數據,誰發生變化我就拿來用給r,windows上只有select
    #    - poll, 內部進行循環操做         主動查看,和select區別是沒有限制,select最大數據1024
    #    - epoll,                        被動告知(邊緣觸發),經過異步回調實現
    r,w,e = select.select(inputs,[],[],0.05)
    # r = [sk2,]    假若有人訪問8002
    # r = [sk1,]    假若有人訪問8001
    # r = [sk1,sk2] 假如同時訪問8002和8001
    # r = []        #0.05是超時時間,假如沒有人訪問就是r就是空列表
    # r = [conn,]
    # r = [sk1,Wconn]
    #######
    for obj in r:                                   #r包含全部的對象,sk1,sk2,sk1.conn,sk2.conn
        if obj in [sk1,sk2]:
            # 新鏈接撿來了...
            print('新鏈接來了:',obj)
            conn,addr = obj.accept()                #conn這裏有鏈接來了纔會往下執行,不然會卡在等待鏈接
            inputs.append(conn)
        else:
            # 有鏈接用戶發送消息來了..
            print('有用戶發送數據了:',obj)
            data = obj.recv(1024)                   #創建完鏈接後客戶端發數據了纔會往下走,不然會一直等着收數據
            obj.sendall(data)
io多路複用服務端
import socket

client = socket.socket()
client.connect(('127.0.0.1',8003,))

while True:
    v = input('>>>')
    client.sendall(bytes(v,encoding='utf-8'))
    ret = client.recv(1024)
    print('服務器返回:',ret)
io多路複用客戶端1
import socket

client = socket.socket()
client.connect(('127.0.0.1',8004,))

while True:
    v = input('>>>')
    client.sendall(bytes(v,encoding='utf-8'))
    ret = client.recv(1024)
    print('服務器返回:',ret)
io多路複用客戶端2
#服務端
C:\Python35\python3.exe D:/pycharm/s16/day9/8.IO多路複用.py
新鏈接來了: <socket.socket fd=264, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8003)>
有用戶發送數據了: <socket.socket fd=272, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8003), raddr=('127.0.0.1', 58840)>
新鏈接來了: <socket.socket fd=268, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8004)>
有用戶發送數據了: <socket.socket fd=276, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8004), raddr=('127.0.0.1', 58845)>

#客戶端1
C:\Python35\python3.exe D:/pycharm/s16/day9/9.socket客戶端.py
>>>1
服務器返回: b'1'
>>>


#客戶端2
C:\Python35\python3.exe D:/pycharm/s16/day9/10.socket客戶端.py
>>>2
服務器返回: b'2'
>>>
輸出

2.io多路複用優化

# -*- coding: UTF-8 -*-
#blog:http://www.cnblogs.com/linux-chenyang/
#r裏面只接受,w發送

import socket
import select

# IO多路複用:8002,8001
#

sk1 = socket.socket()
sk1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
sk1.bind(('127.0.0.1',8003,))
sk1.listen(5)

sk2 = socket.socket()
sk2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
sk2.bind(('127.0.0.1',8004,))
sk2.listen(5)
inputs = [sk1,sk2,]
w_inputs = []
while True:
    # IO多路複用,同時監聽多個socket對象
    #    - select,內部進行循環操做(1024)  在系統底層主動查看有沒有人給我發來數據,誰發生變化我就拿來用給r,windows上只有select
    #    - poll, 內部進行循環操做         主動查看,和select區別是沒有限制,select最大數據1024
    #    - epoll,                        被動告知(邊緣觸發),經過異步回調實現
    r,w,e = select.select(inputs,w_inputs,inputs,0.05)
    # r = [sk2,]    假若有人訪問8002
    # r = [sk1,]    假若有人訪問8001
    # r = [sk1,sk2] 假如同時訪問8002和8001
    # r = []        #0.05是超時時間,假如沒有人訪問就是r就是空列表
    # r = [conn,]
    # r = [sk1,Wconn]
    #######
    for obj in r:                                   #r包含全部的對象,sk1,sk2,sk1.conn,sk2.conn
        if obj in [sk1,sk2]:
            # 新鏈接撿來了...
            print('新鏈接來了:',obj)
            conn,addr = obj.accept()                #conn這裏有鏈接來了纔會往下執行,不然會卡在等待鏈接
            inputs.append(conn)
        else:
            # 有鏈接用戶發送消息來了..
            print('有用戶發送數據了:',obj)
            try:
                data = obj.recv(1024)                   #創建完鏈接後客戶端發數據了纔會往下走,不然會一直等着收數據
            except Exception as ex:
                data=''
            if data:                                    #假如收到了數據,就在發送
                #obj.sendall(data)
                w_inputs.append(obj)
            else:
                obj.close()
                inputs.remove(obj)
                w_inputs.remove(obj)

    for obj in w:
        obj.sendall(b'ok')
        w_inputs.remove(obj)
優化

3.模擬sockserver

import socket
import select
import threading

# IO多路複用:8002,8001
#
############################### 基於select實現服務端的「僞」併發 ###############################
"""
def process_request(conn):
    while True:
        v = conn.recv(1024)
        conn.sendall(b'1111')

sk1 = socket.socket()
sk1.bind(('127.0.0.1',8001,))
sk1.listen(5)
inputs=[sk1,]
while True:
    # IO多路複用,同時監聽多個socket對象
    #    - select,內部進行循環操做(1024)  主動查看
    #    - poll, 內部進行循環操做         主動查看
    #    - epoll,                        被動告知
    r,w,e = select.select(inputs,[],inputs,0.05)

    for obj in r:
        if obj in sk1:
            # conn客戶端的socket
            conn,addr = obj.accept()
            t = threading.Thread(target=process_request,args=(conn,))
            t.start()
"""
# import socketserver
#
# class MyHandler(socketserver.BaseRequestHandler):
#     def handle(self):
#         pass
#
#
# server = socketserver.ThreadingTCPServer(('127.0.0.1',8001),MyHandler)
# server.serve_forever()
模擬

 

 

 

 

 

 

 

 

 

 

greenlet
相關文章
相關標籤/搜索