併發編程十二問

来源:https://www.cnblogs.com/lfs2640666960/archive/2018/09/03/9581622.html
-Advertisement-
Play Games

1、簡述電腦操作系統中的“中斷”的作用? 2、簡述電腦記憶體中的“內核態”和“用戶態”; 3、進程間通信方式有哪些? 4、簡述你對管道、隊列的理解; 5、請列舉你知道的進程間通信方式; 6、什麼是同步I/O,什麼是非同步I/O? 7、請問multiprocessing模塊中的Value、Array類 ...


1、簡述電腦操作系統中的“中斷”的作用?

電腦操作系統的中斷的作用:cpu會切:io阻塞,程式運行時間過長

    中斷:電腦執行期間,系統內發生任何非尋常的或非預期的急需處理事件,使得
cpu暫時中斷當前正在執行的程式而轉去執行相應的事件處理程式。
    
    待處理完畢後又返回原來被中斷處理急需執行或者調度新的進程執行的過程,它使計算
機可以更好更快的利用有限的系統資源解決系統響應速度和運行效率的一種控制技術:
    實時響應 + 系統調用
    
    中斷裝置是由一些特定的寄存器和控制線路組成,中央處理器和外圍設備等識別到的
事件保存在特定的寄存器中。
    中央處理器每執行完一條指令,均有中斷裝置判別是否有事件發生。
    若無事件發生,CPU繼續執行。
    若有事件發生,則中斷裝置中斷原占有CPU的程式的執行,讓操作系統的處理事件服
務程式占用CPU,對出現的事件進行處理,事件處理完後,再讓原來的程式繼續占用CPU執行

 

2、簡述電腦記憶體中的“內核態”和“用戶態”;

操作系統的核心是內核,獨立於普通的應用程式,內核可以訪問受保護的記憶體空間,
也可以訪問底層硬體設備的所有許可權,為了保證用戶進程不能直接操作內核,保證內核
的安全,操作系統將虛擬空間劃分為兩部分,一部分是內核空間,一部分是用戶空間。

    內核態:運行操作系統的程式,os的數據存放
    
    用戶態:運行用戶程式,用戶進程的數據存放

    用戶態的應用程式可以通過三種方式來訪問內核態的資源:
        1)系統調用
        2)庫函數
        3)Shell腳本
    用戶態到內核態的切換:
        1.系統調用        用戶程式主動發起的 軟中斷 os.fork() process
        2.異常            被動的   當CPU正在執行運行在用戶態的程式時,突然發生某些預
先不可知的異常事件,這個時候就會觸發從當前用戶態執行的進程轉向內核態執行相關的
異常事件,典型的如缺頁異常。

        3.外圍設備的硬中斷  被動的   外圍設備完成用戶的請求操作後,會像CPU發出中斷信號,
此時,CPU就會暫停執行下一條即將要執行的指令,轉而去執行中斷信號對應的處理程式,
如果先前執行的指令是在用戶態下,則自然就發生從用戶態到內核態的轉換。

 

3、進程間通信方式有哪些?

進程間通信(IPC)
    消息隊列(    隊列 = 管道 + 鎖)
    管道(使用消息傳遞的)
    有名管道(FIFO)
    信號量
    共用記憶體
    套接字(socket)

 

4、簡述你對管道、隊列的理解;

管道通常指無名管道
1、它是半雙工的(即數據只能在一個方向上流動),具有固定的讀端和寫端
2、它只能用於具有親緣關係的進程中通信(也就是父與子進程或者兄弟進程之間)
3、數據不可反覆讀取了,即讀了之後歡喜紅區中就沒有了
消息隊列
1、消息隊列是面向記錄的,其中的消息具有特定的格式以及特定的優先順序
2、消息隊列獨立於發送與接收進程。進程終止時,消息隊列及其內容不會被刪除。
3、消息隊列可以實現消息隨機查詢。

    隊列 = 管道 + 鎖

 

5、請列舉你知道的進程間通信方式;

隊列,信號量,Event事件,定時器Timer,線程queue,進程池線程池,非同步調用+回調機制

 

6、什麼是同步I/O,什麼是非同步I/O?

同步IO指的是同步傳輸 ,當發送一個數據請求時,會一直等待,直到有返回結果為止

        非同步IO指的是非同步傳輸 ,當發送一個數據請求時,會立即去處理別的事情,當有數據
處理完畢後,會自動的返回結果
 
    一般同步傳輸能保證數據正確性 ,而非同步能最大化性能。 
    如給u盤複製一個大的數據文件,你開了緩衝優化,是非同步 工作, 複製的快了, 
    你要是剛複製完了直接拔 會丟數據, 
     你要是關了,複製的慢了,但你要是關了緩衝優化,複製完了直接拔 不會丟數據,

非同步IO
    用戶進程發起read操作之後,立刻就可以開始去做其它的事。而另一方
面,從kernel的角度,當它受到一個asynchronous read之後,首先它會
立刻返回,所以不會對用戶進程產生任何block。然後,kernel會等待數據
準備完成,然後將數據拷貝到用戶記憶體,當這一切都完成之後,kernel會給
用戶進程發送一個signal,告訴它read操作完成了。

 

7、請問multiprocessing模塊中的Value、Array類的作用是什麼?舉例說明它們的使用場景

通常,進程之間彼此是完全孤立的,唯一的通信方式是隊列或者管道,但是可以使用兩個對象來表示共用數據。其實這些對象使用了共用記憶體(通過mmap模塊)使訪問多個進程成為可能。

Value( typecode, arg1, … argN, lock ) 

    在共用內容中常見ctypes對象。typecode要麼是包含array模塊使用的相同類型代碼
(如’i’,’d’等)的字元串,要麼是來自ctypes模塊的類型對象(如ctypes.c_int、
ctypes.c_double等)。
    所有額外的位置參數arg1, arg2 ….. argN將傳遞給指定類型的構造函數。lock是只能
使用關鍵字調用的參數,如果把它置為True(預設值),將創建一個新的鎖定來包含對值的訪問。
    如果傳入一個現有鎖定,比如Lock或RLock實例,該鎖定將用於進行同步。如果v是Value創建
的共用值的實例,便可使用v.value訪問底層的值。例如,讀取v.value將獲取值,而賦值v.value
將修改值。

  RawValue( typecode, arg1, … ,argN) 
同Value對象,但不存在鎖定。

  Array( typecode, initializer, lock ) 
    在共用記憶體中創建ctypes數組。typecode描述了數組的內容,意義與Value()函數中的相同。
initializer要麼是設置數組初始大小的整數,要麼是項目序列,其值和大小用於初始化數組。
lock是只能使用關鍵字調用的參數,意義與Value()函數中相同。
    如果a是Array創建的共用數組的實例,便可使用標準的python索引、切片和迭代操作訪問它
的內容,其中每種操作均由鎖定進行同步。對於位元組字元串,a還具有a.value屬性,可以吧整個
數組當做一個字元串進行訪問。

  RawArray(typecode, initializer ) 
    同Array對象,但不存在鎖定。當所編寫的程式必須一次性操作大量的數組項時,如果同時
使用這種數據類型和用於同步的單獨鎖定(如果需要的話),性能將得到極大的提升。

應該註意,使用多進程後,通常不必再擔心與鎖定、信號量或類似構造的底層同步,這一點與線程不相伯仲。在某種程度上,管道上的send()和receive()操作,以及隊列上的put()和get()操作已經提供了同步功能。但是,在某寫特定的設置下還是需要用到共用值和鎖定。下麵這個例子說明瞭如何使用共用數組代替管道,將一個浮點數的python列表發送給另一個進程:

import multiprocessing
class FloatChannel(object):
    def __init__(self,maxsize):
        self.buffer=multiprocessing.RawArray('d',maxsize)
        self.buffer_len=multiprocessing.Value('i')
        self.empty=multiprocessing.Semaphore(1)
        self.full=multiprocessing.Semaphore(0)
    def send(self,values):
        self.empty.acquire()  #只在緩存為空時繼續
        nitems=len(values)  
        self.buffer_len=nitems  #設置緩衝區大小
        self.buffer[:nitems]=values #將複製到緩衝區中
        self.full.release() #發信號通知緩衝區已滿
    def recv(self):
        self.full.acquire()     #只在緩衝區已滿時繼續
        values=self.buffer[:self.buffer_len.value]  #複製值
        self.empty.release()        #發送信號通知緩衝區為空
        return values
    #性能測試 接收多條消息
def consume_test(count,ch):
    for i in xrange(count):
        values=ch.recv()

#性能測試 發送多條消息
def produce_test(count,values,ch):
    for i in xrange(count):
        ch.send(values)
if __name__=="__main__":
    ch=FloatChannel(100000)
    p=multiprocessing.Process(target=consume_test,args=(1000,ch))
    p.start()
    values=[float(x) for x in xrange(100000)]
    produce_test(1000,values,ch)
    print "Done"
    p.join()

 

8、請問multiprocessing模塊中的Manager類的作用是什麼?與Value和Array類相比,Manager的優缺點是什麼?

可以通過使用Value或者Array把數據存儲在一個共用的記憶體表中;Manager()返回一個manager類型,控制一個server process,可以允許其它進程通過代理複製一些python objects   支持list,dict,Namespace,Lock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value,Array ;

Manager類的作用共用資源,manger的的優點是可以在poor進程池中使用,缺點是windows下環境下性能比較差,因為windows平臺需要把Manager.list放在if name =' main '下,而在實例化子進程時,必須把Manager對象傳遞給子進程,否則lists無法被共用,而這個過程會消耗巨大資源,因此性能很差。

multiprocessing 是一個使用方法類似threading模塊的進程模塊。允許程式員做並行開發。並且可以在UNIX和Windows下運行。

通過創建一個Process 類型並且通過調用call()方法spawn一個進程。

一個比較簡單的例子:

from multiprocessing import Process
import time
def f(name):
time.sleep(1)
print 'hello ',name
print os.getppid() #取得父進程ID
print os.getpid()  #取得進程ID
process_list = []
if __name__ == '__main__':
for i in range(10):
p = Process(target=f,args=(i,))
p.start()
process_list.append(p)
for j in process_list:
j.join()

進程間通信:

有兩種主要的方式:Queue、Pipe

1- Queue類幾乎就是Queue.Queue的複製,示例:

from multiprocessing import Process,Queue
import time
def f(name):
time.sleep(1)
q.put(['hello'+str(name)])
process_list = []
q = Queue()
if __name__ == '__main__':
for i in range(10):
p = Process(target=f,args=(i,))
p.start()
process_list.append(p)
for j in process_list:
j.join()
for i in range(10):
print q.get()

2- Pipe 管道

from multiprocessing import Process,Pipe
import time
import os

def f(conn,name):
time.sleep(1)
conn.send(['hello'+str(name)])
print os.getppid(),'-----------',os.getpid()
process_list = []
parent_conn,child_conn = Pipe()
if __name__ == '__main__':
for i in range(10):
p = Process(target=f,args=(child_conn,i))
p.start()
process_list.append(p)
for j in process_list:
j.join()
for p in range(10):
print parent_conn.recv()

Pipe()返回兩個連接類,代表兩個方向。如果兩個進程在管道的兩邊同時讀或同時寫,會有可能造成corruption.

進程間同步

multiprocessing contains equivalents of all the synchronization primitives from threading.

例如,可以加一個鎖,以使某一時刻只有一個進程print

from multiprocessing import Process,Lock
import time
import os

def f(name):
lock.acquire()
time.sleep(1)
print 'hello--'+str(name)
print os.getppid(),'-----------',os.getpid()
lock.release()
process_list = []
lock = Lock()
if __name__ == '__main__':
for i in range(10):
p = Process(target=f,args=(i,))
p.start()
process_list.append(p)
for j in process_list:
j.join()

進程間共用狀態 Sharing state between processes

當然盡最大可能防止使用共用狀態,但最終有可能會使用到.

1-共用記憶體

可以通過使用Value或者Array把數據存儲在一個共用的記憶體表中

from multiprocessing import Process,Value,Array
import time
import os

def f(n,a,name):
time.sleep(1)
n.value = name * name
for i in range(len(a)):
a[i] = -i
process_list = []
if __name__ == '__main__':
num = Value('d',0.0)
arr = Array('i',range(10))
for i in range(10):
p = Process(target=f,args=(num,arr,i))
p.start()
process_list.append(p)
for j in process_list:
j.join()
print num.value
print arr[:]
輸出:
james@James:~/projects$ python pp.py 
81.0
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

'd'和'i'參數是num和arr用來設置類型,d表示一個雙精浮點類型,i表示一個帶符號的整型。

更加靈活的共用記憶體可以使用multiprocessing.sharectypes模塊

Server process

Manager()返回一個manager類型,控制一個server process,可以允許其它進程通過代理複製一些python objects

支持list,dict,Namespace,Lock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value,Array

from multiprocessing import Process,Manager
import time
import os

def f(d,name):
time.sleep(1)
d[name] = name * name
print d
process_list = []
if __name__ == '__main__':
manager = Manager()
d = manager.dict()
for i in range(10):
p = Process(target=f,args=(d,i))
p.start()
process_list.append(p)
for j in process_list:
j.join()
print d
輸出結果:
{2: 4}
{2: 4, 3: 9}
{2: 4, 3: 9, 4: 16}
{1: 1, 2: 4, 3: 9, 4: 16}
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 8: 64}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

Server process managers比共用記憶體方法更加的靈活,一個單獨的manager可以被同一網路的不同電腦的多個進程共用。比共用記憶體更加的緩慢

使用工作池Using a pool of workers

Pool類代表 a pool of worker processes.

It has methods which allows tasks to be offloaded to the worker processes in a few different ways.

9、寫一個程式,包含十個線程,子線程必須等待主線程sleep 10秒鐘之後才執行,並列印當前時間;

# _*_ coding: utf-8 _*_ 
# 寫一個程式,包含十個線程,子線程必須等待主線程sleep 10秒鐘
# 之後才執行,並列印當前時間
from threading import Thread
import time

def task(name):
        print(name,time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))

if __name__ == '__main__':
    time.sleep(2)
    for i in range(10):
        t = Thread(target=task,args=('線程 %s'%i,))
        t.start()

 

10、寫一個程式,包含十個線程,同時只能有五個子線程並行執行;

# _*_ coding: utf-8 _*_ 
# 10、寫一個程式,包含十個線程,同時只能有五個子線程並行執行;
from threading import Thread
from threading import currentThread
from concurrent.futures import ThreadPoolExecutor
import time
import random

def task():
    print(currentThread().getName())
    time.sleep(random.randint(1,3))

if __name__ == '__main__':
    pool = ThreadPoolExecutor(5)
    for i in range(10):
        pool.submit(task)

 

11、寫一個程式,要求用戶輸入用戶名和密碼,要求密碼長度不少於6個字元,且必須以字母開頭,如果密碼合法,則將該密碼使用md5演算法加密後的十六進位概要值存入名為password.txt的文件,超過三次不合法則退出程式;

# _*_ coding: utf-8 _*_ 
# 11、寫一個程式,要求用戶輸入用戶名和密碼,要求密碼
# 長度不少於6個字元,且必須以字母開頭,如果密碼合法,
# 則將該密碼使用md5演算法加密後的十六進位概要值存入名
# 為password.txt的文件,超過三次不合法則退出程式;
import re
import hashlib
import pickle

def func():
    count = 0
    while count<3:
        username = input("username>>>").strip()
        password = input("password>>>").strip()
        if len(password) >=6 and re.search('\A([a-z)|[A-Z])',password):
            md5_password =  hashlib.md5(password.encode('utf-8')).hexdigest()
            file_obj = {'username':username,
                        'passworf':md5_password}
            f = open('password.txt','ab')
            pickle.dump(file_obj,f)
            break
        else:
            print("請輸入合法的密碼")
            count +=1
    else:
        print("您的機會已經用完")
if __name__ == '__main__':
    func()

 

12、寫一個程式,使用socketserver模塊,實現一個支持同時處理多個客戶端請求的伺服器,要求每次啟動一個新線程處理客戶端請求;

服務端:

# _*_ coding: utf-8 _*_ 
# 12、寫一個程式,使用socketserver模塊,
# 實現一個支持同時處理多個客戶端請求的伺服器,
# 要求每次啟動一個新線程處理客戶端請求;

import socketserver

class Handler(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            try:
                data = self.request.recv(1024)
                if not data:
                    break
                print('client data',data.decode())
                self.request.send(data.upper())
            except Exception as e:
                print(e)
                break
if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8888),Handler)
    server.serve_forever()

 

客戶端

# _*_ coding: utf-8 _*_ 
import socket
ip_port = ('127.0.0.1',8888)
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(ip_port)
while True:
    msg = input(">>>>").strip()
    if not msg:
        continue
    client.send(msg.encode('utf-8'))
    data = client.recv(1024)
    print(data)

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • c++ move關鍵字 move的由來:在 c++11 以前存在一個有趣的現象:T& 指向 lvalue (左傳引用), const T& 既可以指向 lvalue 也可以指向 rvalue。但卻沒有一種引用類型,可以限製為只指向 rvalue。 就這麼簡單!你甚至可以暫時想像它的原型是這樣的(當然 ...
  • 定義用戶去銀行存錢,每次存100,存3次 餓漢式 懶漢式 多線程 在同一時間,做多件事情. 創建線程的方法 繼承類Thread並重寫run(),run()稱為線程體;用這種方法定義的類不能再繼承其他類。 class FirstThread extends Thread{ public void ru ...
  • 常量池: 字元串一旦被初始化就不會被改變 這段代碼看上去s的值是被改變了的,實際上123就是一個對象,他存在於常量池中,abc也是一個對象,s的值實際上是指向123或者abc的地址。 所以當我們使用String s="123";來定義字元串的時候,會先查看常量池中是否有123,有就直接賦值123的地 ...
  • 前言 從去年八月末開始工作一年了,有了大半年的java開發經驗,自認為比在大學時候編碼能力強了很多,但是基礎方面叫不准的地方感覺越來越多了 (;´д`)ゞ 所以,我準備把這些問題以及工作中遇到的問題總結,記錄下來,造福自己和大家~ヾ(o・ω・)ノ 當然,如果大家發現我哪裡寫的有錯誤,歡迎在下方評論指 ...
  • 在Python3.6.5版本測試通過 語法 str.format(*args, **kwargs) 它通過{}和:來代替%。 "映射”示例: 1.通過位置 In [1]: '{0},{1}'.format('kzc',18) Out[1]: 'kzc,18' In [2]: '{},{}'.form ...
  • 一.基礎配置 1.引入依賴 2.創建主類,通過 @EnableFeginClients 註解開啟 Feign 功能 3.定義AService介面,通過 @FeignClient 註解指定服務名來綁定服務, 然後使用SpringMVC 的註解來綁定具體該服務提供的 REST 介面 需要調用 AServ ...
  • 對文件操作流程如下: 1、打開文件,得到一個文件句柄並賦給一個變數 2、通過文件句柄對文件進行操作 3、關閉文件 4、為了必免打開文件忘記關閉,可以通過上下文管理,即: with open("F:\yesterday2","r",encoding="utf-8") as f: for line in ...
  • c/c++ 右值引用 轉自:https://www.cnblogs.com/catch/p/3500678.html 左值(lvalue)和右值(rvalue)是 c/c++ 中一個比較晦澀基礎的概念,不少寫了很久c/c++的人甚至沒有聽過這個名字,但這個概念到了 c++11 後卻變得十分重要,它們 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...