<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      并行關鍵看是否能同時處理多個任務.依靠多核,同一時間每個CPU上執行一個任務

      并發關鍵看是否能在一段時間內處理多個任務并不要求同時,

      他倆最本質的特點就是是否能同時處理多個任務.無多核無并行

      并行指的是多個CPU,并發主要是針對一個CPU而已,多個任務在一個CPU上交替切換任務。

      并發的目的:充分利用處理器的每一個核,達到最高的處理性能。

      協程線程進程的區別

      協程也被稱為微線程,下面對比一下協程和線程:

      1. 線程之間需要上下文切換成本相對協程來說是比較高的,尤其在開啟線程較多時,但協程的切換成本非常低。
      2. 同樣的線程的切換更多的是靠操作系統來控制,而協程的執行由我們自己控制
      3. 不需要線程的的鎖機制
      進程  數據隔離      數據不安全      切換開銷最大     操作系統控制        能用多核        
      線程   數據共享    數據不安全       切換開銷大         操作系統控制      不能用多核
      
      協程   數據共享     數據安全        切換開銷小        用戶控制         不能用多核

       

       

       

      協程

      引用官方說法:

      協程是一種用戶態的輕量級線程,協程的調度完全由用戶控制。協程擁有自己的寄存器上下文和棧。
      協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操作棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變量,所以上下文的切換非常快。

      并發的本質:就是多個任務在一條線程中來回切換并保存狀態,來實現一條線程上的io降到最低

      線程和進程都是靠操作系統來控制切換+保存狀態的,而協程的是靠用戶來切換和保存狀態。

      既然需要我們自己來控制切換和保存狀態,我們的yield的關鍵字可以解決這個問題,但是有一個關鍵的問題是:什么時候切換?只有遇到io切換才能提高程序效率,

      所以協程最關鍵是用來解決單線程實現并發的io問題的。

       

       

       

      協程也被稱為''微線程'',協程并不是真實存在的,是程序員自己命名的

      cpu正在運行一個任務,會在兩種情況下切走去執行其他的任務(切換由操作系統強制控制),一種情況是該任務發生了阻塞,另外一種情況是該任務計算的時間過長或有一個優先級更高的程序替代了它

      協程的本質 

      協程的本質就是在單線程下,由用戶自己控制一個任務遇到io阻塞就切換另外一個任務去執行,以此來提升單線程的執行效率。為了實現它,我們需要找尋一種可以同時滿足以下條件的解決方案:

      #1. 可以控制多個任務之間的切換,切換之前將任務的狀態保存下來,以便重新運行時,可以基于暫停的位置繼續執行。
      
      #2. 作為1的補充:可以檢測io操作,在遇到io操作的情況下才發生切換

      協程的作用

      1.減少任務切換的開銷。

      2.實現單線程下并發。單線程并發要解決的核心是,解決io,遇到io切換才能提高效率,而對于線程和進程來說io問題已經被操作系統解決了,然后協程需要我們自己來解決io。

      3.最主要的問題是解決io,提高了單線程的執行效率

      協程的優點

      1.切換開銷小,速度快

      2.不需要多線程的鎖機制,因為只有一個線程,也不存在同時寫變量沖突,在協程中控制共享資源不加鎖,只需要判斷狀態就好了,所以執行效率比多線程高很多

      3.可以實現單線程下的并發

      協程的缺點

      1. 協程的本質是單線程下,無法利用多核.

         

      2. 協程指的是單個線程,因而一旦協程出現阻塞,將會阻塞整個線程

        

      線程相當于協程來說的一個優點?
      我們知道線程是靠操作系統的來規避io的,協程是靠用戶規避io的,但是用戶不能規避所有的io,一些文件操作的io(比如print)線程感知比協程更敏感.目前為止協程能感知到的io有請求網絡

       

      greenlet 

      官網https://greenlet.readthedocs.io/en/latest/

      greenlet是一個輕量級的并發編程模塊。它實現了并發但是沒有實現協程,因為協程要求遇到io才切換。

      官網例子:

      from greenlet import greenlet
      
      def test1():
          print(12)
          gr2.switch() #切換到gr2greenlet當調用test2函數
          print(34)
      
      def test2():
          print(56)
          gr1.switch()
          print(78)
      
      gr1 = greenlet(test1) 
      gr2 = greenlet(test2)
      gr1.switch() #當綁定的函數有參數時,從這里傳進去

      我們首先創建兩個greenlet并分別綁定text1和text2,然后執行switch切換到gr1然后執行text1函數打印出12,然后再切換到gr2打印56,然后再切換到gr1因為greenlet能保存狀態所以執行print(78)這個代碼打印出34,text結束由于此時沒有切換到gr2 78不會被打印出來

      結果

      12
      56
      34

       

      greenlet 的模塊和yield并沒有什么區別,在協程中只是單純的來切換任務,并沒有解決效率問題,只有遇到io的時候切換才會有效率

      如果我們在單個線程內有20個任務,要想實現在多個任務之間切換,使用yield生成器的方式過于麻煩(需要先得到初始化一次的生成器,然后再調用send。。。非常麻煩),而使用greenlet模塊可以非常簡單地實現這20個任務直接的切換

      from greenlet import greenlet
      import time
      
      def eat(name):
          print('%s eat 1' %name)
          time.sleep(1)
          g2.switch('egon')
          print('%s eat 2' %name)
          g2.switch()
      def play(name):
          print('%s2 play 1' %name)
          g1.switch()
          print('%s2 play 2' %name)
      
      g1=greenlet(eat)
      g2=greenlet(play)
      
      g1.switch('egon')#可以在第一次switch時傳入參數,以后都不需要

       

      結果:

      egon eat 1
      egon2 play 1
      egon eat 2
      egon2 play 2

       

      總結:greenlet只是提供了一種比生成器更加便捷的切換方式,當切到一個任務執行時如果遇到io,那就原地阻塞,仍然是沒有解決遇到IO自動切換來提升效率的問題。

      gevent

      Gevent 是一個第三方庫,可以通過gevent實現協程,進而實現并發編程,在genent中用到的主要模塊就是greenlet,該模塊用c語言寫的,它比greenlet模塊多了一個可以檢測出io再切換

      主要思想是:

      當一個greenlet遇到io操作時,比如說訪問網站,就自動切換到其他的greenlet,等待io操作完成再在適當的時候切換回來繼續執行,由于IO操作非常耗時,經常使程序處于等待狀態,有了gevent為我們自動切換協程,就保證總有greenlet在運行,而不是等待IO。

       作用:

      1. 切換+保存狀態
      2. 自動能檢測到io
      3. 遇到io切換任務

       

      gevent可以規避哪些io

      def patch_all(socket=True, dns=True, time=True, select=True, thread=True, os=True, ssl=True,
                    httplib=False, # 這里就表明了不支持網絡io也就是說請求網頁的io
                    subprocess=True, sys=False, aggressive=True, Event=True,
                    builtins=True, signal=True,
                    queue=True,
                    **kwargs):

       

       

      from gevent import monkey
      monkey.patch_all() #這個方法就是為了監聽代碼下邊的所有的io操作,必須寫在代碼的開頭
      
      import gevent
      import time
      
      def eat(name):
          print('%s eat 1' %name)
         gevent.sleep(2) #其實就是genvent.sleep可以識別io操作,有io后直接切換到下一個任務
      print('%s eat 2' %name)
          return 'eat'
      
      def play(name):
          print('%s play 1' %name)
          gevent.sleep(1)
      print('%s play 2' %name)
          return 'play'
      
      start=time.time()
      g1=gevent.spawn(eat,"小紅") #創建協程對象,spawn括號內第一個參數是函數名,如eat,后面可以有多個參數,可以是位置實參或關鍵字實參,都是傳給函數eat的
      
      g2=gevent.spawn(play,'小明') #這也是異步提交
      
      g1.join()#等待g1完成
      g2.join()#等待g完成
      #或者把上面兩步何為一步 gevent.joinall([g1,g2])
      print("主線程開始運行",time.time()-start)
      print(g1.value,g2.value) #拿到上述函數的返回值

      結果:

      小紅 eat 1
      小明 play 1
      小明 play 2
      小紅 eat 2
      主線程開始運行 2.003354787826538
      eat play

       gevent 的應用

      例子1爬蟲

      from gevent import monkey;monkey.patch_all()
      import gevent
      import requests
      import time
      
      def get_page(url):
          print('GET: %s' %url)
          response=requests.get(url)
          if response.status_code == 200:
              print('%d bytes received from %s' %(len(response.text),url))
      
      
      start_time=time.time()
      gevent.joinall([
          gevent.spawn(get_page,'https://www.python.org/'),
          gevent.spawn(get_page,'https://www.yahoo.com/'),
          gevent.spawn(get_page,'https://github.com/'),
      ])
      stop_time=time.time()
      print('run time is %s' %(stop_time-start_time))
      View Code

      結果:

      59631 bytes received from https://github.com/
      499780 bytes received from https://www.yahoo.com/
      48823 bytes received from https://www.python.org/
      run time is 1.8453788757324219
      View Code

      使用asyncio來實現上邊的爬蟲

      import asyncio
      import aiohttp
      import time
      
      async def get_page(url):
          async with aiohttp.ClientSession() as session:
              async with session.get(url) as response:
                  if response.status == 200:
                      content = await response.text()
                      print(f'{len(content)} bytes received from {url}')
      
      async def main():
          tasks = [
              get_page('https://www.python.org/'),
              get_page('https://www.yahoo.com/'),
              get_page('https://github.com/'),
          ]
          await asyncio.gather(*tasks)
      
      if __name__ == '__main__':
          start_time = time.time()
          asyncio.run(main())
          stop_time = time.time()
          print('run time is %s' % (stop_time - start_time))

       

       

      例子2 socket的服務端和客戶端的并發

      from gevent import monkey;monkey.patch_all()
      from socket import *
      import gevent
      
      #如果不想用money.patch_all()打補丁,可以用gevent自帶的socket
      # from gevent import socket
      # s=socket.socket()
      
      def server(server_ip,port):
          s=socket(AF_INET,SOCK_STREAM)
          s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
          s.bind((server_ip,port))
          s.listen(5)
          while True:
              conn,addr=s.accept()
              gevent.spawn(talk,conn,addr)
      
      def talk(conn,addr):
          try:
              while True:
                  res=conn.recv(1024)
                  print('client %s:%s msg: %s' %(addr[0],addr[1],res))
                  conn.send(res.upper())
          except Exception as e:
              print(e)
          finally:
              conn.close()
      
      if __name__ == '__main__':
          server('127.0.0.1',8080)
      
      服務端
      
      服務端
      服務端
      #_*_coding:utf-8_*_
      __author__ = 'Linhaifeng'
      
      from socket import *
      
      client=socket(AF_INET,SOCK_STREAM)
      client.connect(('127.0.0.1',8080))
      
      
      while True:
          msg=input('>>: ').strip()
          if not msg:continue
      
          client.send(msg.encode('utf-8'))
          msg=client.recv(1024)
          print(msg.decode('utf-8'))
      
      客戶端
      客戶端
      from threading import Thread
      from socket import *
      import threading
      
      def client(server_ip,port):
          c=socket(AF_INET,SOCK_STREAM) #套接字對象一定要加到函數內,即局部名稱空間內,放在函數外則被所有線程共享,則大家公用一個套接字對象,那么客戶端端口永遠一樣了
          c.connect((server_ip,port))
      
          count=0
          while True:
              c.send(('%s say hello %s' %(threading.current_thread().getName(),count)).encode('utf-8'))
              msg=c.recv(1024)
              print(msg.decode('utf-8'))
              count+=1
      if __name__ == '__main__':
          for i in range(500):
              t=Thread(target=client,args=('127.0.0.1',8080))
              t.start()
      
      多線程并發多個客戶端
      多線程并發客戶端

       asyncio

      asyncio是Python 3.4版本引入的標準庫,直接內置了對異步IO的支持。

      asyncio的編程模型就是一個消息循環。我們從asyncio模塊中直接獲取一個EventLoop的引用,然后把需要執行的協程扔到EventLoop中執行,就實現了異步IO。

      注意asyncio在Python3.7中做出了改變,建議以后使用Python3.7以上的版本

      有一個很好的博客

       https://blog.csdn.net/qq_42658739/article/details/128437355

       

      posted on 2018-05-12 00:19  程序員一學徒  閱讀(722)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 欧美牲交a欧美牲交aⅴ免费 | 高淳县| 久久精品国产一区二区三| 亚洲精品专区永久免费区| 国产AV国片精品有毛| 西西444www高清大胆| 成人网站免费在线观看| 欧美福利电影A在线播放| 中文字字幕在线中文乱码| 无码av中文字幕久久专区| 久久精产国品一二三产品| 拍摄av现场失控高潮数次| 国产一精品一av一免费爽爽 | 在线a级毛片无码免费真人| 欧美中文亚洲v在线| 蜜芽久久人人超碰爱香蕉| 色综合热无码热国产| 国产亚洲精品第一综合麻豆| 亚洲综合在线日韩av| 国产精品麻豆欧美日韩ww | 国产精品男女午夜福利片| 国产日韩一区二区天美麻豆| 亚洲欧美综合人成在线| 亚洲精品国产老熟女久久| 中文字幕午夜福利片午夜福利片97| 色欲国产精品一区成人精品| 国产一级小视频| 强伦姧人妻免费无码电影| 亚洲理论在线A中文字幕| 精品少妇人妻av无码专区| √天堂中文在线最新版| 福利一区二区在线观看| 久久99精品久久久久麻豆| 俄罗斯少妇性XXXX另类| 高清中文字幕国产精品| 国产精品无码专区| 国产普通话对白刺激| 国产精品无码素人福利不卡| 你懂的在线视频一区二区| 亚洲精品美女久久久久9999| 亚洲熟妇少妇任你躁在线观看无码|