進程
- 進程間內存是否共享?如何實現通訊?
進程間內存不共享,可以通過
- Manage模塊加鎖
- 通過隊列或
- 通過管道加鎖
- socket實現通訊
- 請聊聊進程隊列的特點和實現原理?
- 先進先出 Queue
- 后進先出 LifoQueue
- 優先級隊列 PriorityQueue
- 線程本身帶鎖通過put()數據和get()數據,同一時間只有一個線程運行修改任務實現數據安全
- 請畫出進程的三狀態轉換圖
就緒====運行
\阻塞/
yield:
def consumer():
n = yield
n = yield
n = yield
n = yield
n = yield
n = yield
n = yield
n = yield
def producer():
g = consumer()
next(g)
for i in range(2000000):
g.send(i)
- 從你的角度說說進程在計算機中扮演什么角色?
進程在計算機中扮演數據集的調用調配角色。
負責回收和控制子線程的運行,是一個數據集。
##線程
- GIL鎖是怎么回事?
GIL鎖是全局解釋器鎖,只有CPython中使用,同一時間只能有一個線程調度CPU
- 在python中是否線程安全?
不安全,需要加鎖才安全
- 什么叫死鎖?
同時滿足兩個條件鎖才能解開,分別有兩把或以上的鎖,有多個線程分別搶占了兩個條件中的鎖,互不釋放造成阻塞,死鎖現象。
- logging模塊是否是線程安全的?
logging模塊是線程安全的,因為使用的是單例設計模式。
- threading.local的作用?
Python提供了 threading.local 類,將這個類實例化得到一個全局對象,
但是不同的線程使用這個對象存儲的數據其它線程不可見(本質上就是不同的線程使用這個對象時為其創建一個獨立的字典)。
- 程序從flaga執行到falgb的時間大致是多少秒?
60s 因為沒有設置守護線程,需要等子線程跑完主線程才結束
import threading
import time
def _wait():
time.sleep(60)
# flag a
t = threading.Thread(target=_wait, daemon=False)
t.start()
# flag b
- 程序從flaga執行到falgb的時間大致是多少秒?
0.01s 因為設置守護線程,子線程等待所有非子線程結束子線程結束。
import threading
import time
def _wait():
time.sleep(60)
# flag a
t = threading.Thread(target=_wait, daemon=True)
t.start()
# flag b
- 程序從flaga執行到falgb的時間大致是多少秒?
60s 因為設置了阻塞需要等待子線程結束主線程才能結束
import threading
import time
def _wait():
time.sleep(60)
# flag a
t = threading.Thread(target=_wait, daemon=True)
t.start()
t.join()
# flag b
- 讀程序,請確認執行到最后number是否一定為0
不一定,因為存在線程安全問題,同一時間修改變量值
import threading
loop = int(1E7)
def _add(loop: int = 1):
global number
for _ in range(loop):
number += 1
def _sub(loop: int = 1):
global number
for _ in range(loop):
number -= 1
number = 0
ta = threading.Thread(target=_add, args=(loop,))
ts = threading.Thread(target=_sub, args=(loop,))
ta.start()
ts.start()
ta.join()
ts.join()
print(number)
- 讀程序,請確認執行到最后number是否一定為0
一定為0 ,因為增刪操作只有一條語句不會產生數據安全問題。
import threading
loop = int(1E7)
def _add(loop: int = 1):
global number
for _ in range(loop):
number += 1
def _sub(loop: int = 1):
global number
for _ in range(loop):
number -= 1
number = 0
ta = threading.Thread(target=_add, args=(loop,))
ts = threading.Thread(target=_sub, args=(loop,))
ta.start()
ta.join()
ts.start()
ts.join()
print(number)
- 讀程序,請確認執行到最后number的長度是否一定為1
不一定為1,因為產生了阻塞可能有數據安全問題。
import threading
loop = int(1E7)
def _add(loop: int = 1):
global numbers
for _ in range(loop):
numbers.append(0)
def _sub(loop: int = 1):
global number
while not numbers:
time.sleep(1E-8)
numbers.pop()
numbers = [0]
ta = threading.Thread(target=_add, args=(loop,))
ts = threading.Thread(target=_sub, args=(loop,))
ta.start()
ta.join()
ts.start()
ts.join()
print(numbers)
- 讀程序,請確認執行到最后number的長度是否一定為1
不一定為1,因為產生了阻塞可能有數據安全問題。
import threading
loop = int(1E7)
def _add(loop: int = 1):
global numbers
for _ in range(loop):
numbers.append(0)
def _sub(loop: int = 1):
global number
while not numbers:
time.sleep(1E-8)
numbers.pop()
numbers = [0]
ta = threading.Thread(target=_add, args=(loop,))
ts = threading.Thread(target=_sub, args=(loop,))
ta.start()
ts.start()
ta.join()
ts.join()
print(numbers)
協程
- 什么是協程?常用的協程模塊有哪些?
在線程遇到阻塞的情況時切換到另一個線程繼續執行,如果遇到阻塞再到另一個線程執行。如果跳轉過的線程轉為就緒狀態就直接執行,
知道程序中沒有阻塞。有gevent,和greenlet.
- 協程中的join是用來做什么用的?它是如何發揮作用的?
協程是遇到阻塞才切換,join負責阻塞開始執行程序。
- 使用協程實現並發的tcp
server端
from gevent import monkey;monkey.patch_all()
import gevent
import time
import random
import socket
sk = socket.socket()
server_addr = ('127.0.0.1',9988)
sk.bind(server_addr)
sk.listen()
def listen(conn):
while True:
msg = conn.recv(1024).decode('utf-8')
if msg == 'q':break
conn.send(msg.upper().encode('utf-8'))
if __name__ == '__main__':
while True:
conn,addr = sk.accept()
gevent.spawn(listen,conn)
- 在一個列表中有多個url,請使用協程訪問所有url,將對應的網頁內容寫入文件保存
from gevent import monkey;monkey.patch_all()
import time
import random
import gevent
from urllib.request import urlopen
url_dic = {
'協程':'http://www.cnblogs.com/Eva-J/articles/8324673.html',
'線程':'http://www.cnblogs.com/Eva-J/articles/8306047.html',
'目錄':'https://www.cnblogs.com/Eva-J/p/7277026.html',
'百度':'http://www.baidu.com',
'sogou':'http://www.sogou.com',
'4399':'http://www.4399.com',
'豆瓣':'http://www.douban.com',
'sina':'http://www.sina.com.cn',
'淘寶':'http://www.taobao.com',
'JD':'http://www.JD.com'
}
def getHtml(url):
ret = urlopen(url)
html = ret.read()
html_file = url.replace('.','_').lstrip('https://').replace('/','_')+'.html'
with open(html_file,mode='wb') as f:
f.write(html)
print(url+'done')
if __name__ == '__main__':
print('start')
lst = list()
for url in url_dic:
ret = gevent.spawn(getHtml,url_dic[url])
lst.append(ret)
for url in lst:
url.join()
print(1)
綜合
- 進程和線程的區別
進程是計算機資源分配的最小單位,線程是cpu調度的最小單位,線程較進程來說較輕量,啟動更迅速。調用更方便
- 進程池、線程池的優勢和特點
進程池一般在高計算的條件下使用,資源消耗更多。
線程池可以運行在一個進程中,執行效率更高,可控cpu使用率。節約資源。
- 線程和協程的異同?
協程,即協作式程序,其思想是,一系列互相依賴的協程間依次使用CPU,每次只有一個協程工作,而其他協程處於休眠狀態。
協程實際上是在一個線程中,只不過每個協程對CUP進行分時,協程可以訪問和使用unity的所有方法和component
線程,多線程是阻塞式的,每個IO都必須開啟一個新的線程,但是對於多CPU的系統應該使用thread,尤其是有大量數據運算的時刻,
但是IO密集型就不適合;而且thread中不能操作unity的很多方法和component
- 請簡述一下互斥鎖和遞歸鎖的異同?
兩者在在單鎖的情況下都可以保證數據的可靠性。
二者唯一的區別是,同一個線程可以多次獲取同一個遞歸鎖,不會產生死鎖。而如果一個線程多次獲取同一個非遞歸鎖,則會產生死鎖。
- 請列舉一個python中數據安全的數據類型?
Queue
- Python中如何使用線程池和進程池
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import ProcessPoolExector
p = ProcessPoolExector(4)
ret = p.submit(func,aa)
print(ret.result())
- 簡述
進程、線程、協程的區別
進程是:一個CPU情況下,多個程序分別使用機器資源(CPU或硬盤等)的概念;
線程是:一個進程情況下,多個執行流程(即線程)分別使用分配給該進程的機器資源的概念;
- 協程是:一個線程情況下,多個執行流程(即協程)由線程控制,分別使用分配給該線程的機器資源的概念;
以及應用場景?
- 多進程:密集CPU任務,需要充分使用多核CPU資源(服務器,大量的並行計算)的時候,用多進程。 multiprocessing
缺陷:多個進程之間通信成本高,切換開銷大。
- 多線程:密集I/O任務(網絡I/O,磁盤I/O,數據庫I/O)使用多線程合適。
threading.Thread、multiprocessing.dummy
缺陷:同一個時間切片只能運行一個線程,不能做到高並行,但是可以做到高並發。
- 多線程請求返回是無序的,那個線程有數據返回就處理那個線程,而協程返回的數據是有序的。
缺陷:單線程執行,處理密集CPU和本地磁盤IO的時候,性能較低。處理網絡I/O性能還是比較高.
- 什么是並行,什么是並發?
並行是同一時間在多個cpu上同時執行多個程序
並發是同一時間在同一個cpu上在不同程序之間切換運行
- 請解釋同步和異步這兩個概念?
同步執行程序需要等待結果
異步執行程序不需要等待結果
- 請談談對異步非阻塞的了解?
執行效率高,可以實現高並發的應用場景
- 簡述信號量的實現原理
- 信號量機制即利用pv操作來對信號量進行處理。什么是信號量?信號量(semaphore)的數據結構為一個值和一個指針,指針指向等待該信號量的下一個進程。信號量的值與相應資源的使用情況有關。當它的值大於0時,表示當前可用資源的數量;
- 當它的值小於0時,其絕對值表示等待使用該資源的進程個數。注意,信號量的值僅能由PV操作來改變。一般來說,信號量S³0時,
- S表示可用資源的數量。執行一次P操作意味着請求分配一個單位資源,因此S的值減1;當S<0時,表示已經沒有可用資源,
- 請求者必須等待別的進程釋放該類資源,它才能運行下去。而執行一個V操作意味着釋放一個單位資源,因此S的值加1;若S£0,
- 表示有某些進程正在等待該資源,因此要喚醒一個等待狀態的進程,使之運行下去。
- 程序中的阻塞有哪些?給程序帶來了哪些影響?
input,sleep,io 程序會等待阻塞完成才會進入就緒隊列,影響程序運行效率
- 請分別用多進程、多線程、協程實現生產者消費者模型?
多進程
import time
import random
from multiprocessing import Process,Queue
def producer(name,que):
for i in range(10):
time.sleep(random.random())
food = '便便💩'
print('%s 生產了一陀%s' % (name,food))
que.put(food)
def consumer(name,que):
while True:
time.sleep(random.random())
food = que.get()
if not food: break
print('%s 吃了一陀%s' % (name,food))
if __name__ == '__main__':
p_l = list()
que = Queue()
p = Process(target=producer,args=('baoyuan',que))
p.start()
p.join()
c = Process(target=consumer,args=('alex',que,))
c.start()
que.put(None)
c.join()
print('全部吃完啦。')
多線程
import time
import random
from queue import Queue
from threading import Thread
def producer(name,que):
for i in range(10):
time.sleep(random.random())
food = '便便💩'
print('%s 生產了一陀%s' % (name,food))
que.put(food)
def consumer(name,que):
while True:
time.sleep(random.random())
food = que.get()
if not food: break
print('%s 吃了一陀%s' % (name,food))
if __name__ == '__main__':
p_l = list()
que = Queue()
p = Thread(target=producer,args=('baoyuan',que))
p.start()
p.join()
c = Thread(target=consumer,args=('alex',que,))
c.start()
que.put(None)
c.join()
print('全部吃完啦。')
協程
from gevent import monkey;monkey.patch_all()
from queue import Queue
import gevent
import random
import time
def producer(name,que):
for i in range(10):
time.sleep(random.random())
food = '便便💩'
print('%s 生產了一陀%s' % (name,food))
que.put(food)
def consumer(name,que):
while True:
time.sleep(random.random())
food = que.get()
if not food: break
print('%s 吃了一陀%s' % (name,food))
if __name__ == '__main__':
p_l = list()
que = Queue()
p = gevent.spawn(producer,'baoyuan',que)
p.join()
c = gevent.spawn(consumer,'alex',que)
que.put(None)
c.join()
print('全部吃完啦。')