1. 程式人生 > >併發、並行、多執行緒基礎

併發、並行、多執行緒基礎

目錄

什麼是併發

什麼是並行

併發與並行的區別

處理併發問題

HTML靜態化

圖片伺服器分離

資料庫叢集和庫表雜湊

快取

映象

負載均衡

Python 多執行緒

一個新執行緒

執行緒模組

執行緒優先順序佇列( Queue)


什麼是併發

併發,在作業系統中,是指一個時間段中有幾個程式都處於已啟動執行到執行完畢之間,且這幾個程式都是在同一個處理機上執行,但任一個時刻點上只有一個程式在處理機上執行。當有多個執行緒在操作時,如果系統只有一個CPU,則它根本不可能真正同時進行一個以上的執行緒,它只能把CPU執行時間劃分成若干個時間段,再將時間 段分配給各個執行緒執行

,在一個時間段的執行緒程式碼執行時,其它執行緒處於掛起狀。.這種方式我們稱之為併發(Concurrent)。

什麼是並行

當系統有一個以上CPU時,則執行緒的操作有可能非併發。當一個CPU執行一個執行緒時,另一個CPU可以執行另一個執行緒,兩個執行緒互不搶佔CPU資源,可以同時進行,這種方式我們稱之為並行(Parallel)。

併發與並行的區別

併發和並行是即相似又有區別的兩個概念,並行是指兩個或者多個事件在同一時刻發生;而併發是指兩個或多個事件在同一時間間隔內發生。多道程式環境下,併發性是指在一段時間內巨集觀上有多個程式在同時執行,但在單處理機系統中,每一時刻卻僅能有一道程式執行,故微觀上這些程式只能是分時地交替執行。倘若在

計算機系統中有多個處理機,則這些可以併發執行的程式便可被分配到多個處理機上,實現並行執行,即利用每個處理機來處理一個可併發執行的程式,這樣,多個程式便可以同時執行。

處理併發問題

HTML靜態化

效率最高、消耗最小的就是純靜態化的html頁面,所以我們儘可能使我們的網站上的頁面採用靜態頁面來實現,這個最簡單的方法其實也是最有效的方法。

圖片伺服器分離

將圖片與頁面進行分離,這是基本上大型網站都會採用的策略,他們都有獨立的圖片伺服器,甚至很多臺圖片伺服器。這樣的架構可以降低提供頁面訪問請求的伺服器系統壓力,並且可以保證系統不會因為圖片問題而崩潰,在應用伺服器和圖片伺服器上,可以進行不同的配置優化

資料庫叢集和庫表雜湊

在應用程式中安裝業務和應用或者功能模組將資料庫進行分離,不同的模組對應不同的資料庫或者表,再按照一定的策略對某個頁面或者功能進行更小的資料庫雜湊,最終可以在配置檔案中進行簡單的配置便能讓系統隨時增加一臺低成本的資料庫進來補充系統性能。

快取

架構方面的快取,對Apache比較熟悉的人都能知道Apache提供了自己的快取模組,也可以使用外加的Squid模組進行快取,這兩種方式均可以有效的提高Apache的訪問響應能力。

網站程式開發方面的快取,Linux上提供的Memory Cache是常用的快取介面,可以在web開發中使用,比如用Java開發的時候就可以呼叫MemoryCache對一些資料進行快取和通訊共享,一些大型社群使用了這樣的架構。另外,在使用web語言開發的時候,各種語言基本都有自己的快取模組和方法,PHP有Pear的Cache模組,Java就更多了,.net不是很熟悉,相信也肯定有。

映象

映象是大型網站常採用的提高效能和資料安全性的方式,映象的技術可以解決不同網路接入商和地域帶來的使用者訪問速度差異,

負載均衡

1.軟體四層交換,2.硬體四層交換   ------------------以上來自 百度

Python 多執行緒

多執行緒類似於同時執行多個不同程式,多執行緒執行有如下優點:

  • 使用執行緒可以把佔據長時間的程式中的任務放到後臺去處理。
  • 使用者介面可以更加吸引人,這樣比如使用者點選了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度
  • 程式的執行速度可能加快
  • 在一些等待的任務實現上如使用者輸入、檔案讀寫和網路收發資料等,執行緒就比較有用了。在這種情況下我們可以釋放一些珍貴的資源如記憶體佔用等等。

執行緒在執行過程中與程序還是有區別的。每個獨立的程序有一個程式執行的入口、順序執行序列和程式的出口。但是執行緒不能夠獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。

每個執行緒都有他自己的一組CPU暫存器,稱為執行緒的上下文,該上下文反映了執行緒上次執行該執行緒的CPU暫存器的狀態。

指令指標和堆疊指標暫存器是執行緒上下文中兩個最重要的暫存器,執行緒總是在程序得到上下文中執行的,這些地址都用於標誌擁有執行緒的程序地址空間中的記憶體。

  • 執行緒可以被搶佔(中斷)。
  • 在其他執行緒正在執行時,執行緒可以暫時擱置(也稱為睡眠) -- 這就是執行緒的退讓。

一個新執行緒


#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import thread
import time
 
# 為執行緒定義一個函式
def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print "%s: %s" % ( threadName, time.ctime(time.time()) )
 
# 建立兩個執行緒
try:
   thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print "Error: unable to start thread"
 
while 1:
   pass

執行緒的結束一般依靠執行緒函式的自然結束;也可以線上程函式中呼叫thread.exit(),他丟擲SystemExit exception,達到退出執行緒的目的。

執行緒模組

Python通過兩個標準庫thread和threading提供對執行緒的支援。thread提供了低級別的、原始的執行緒以及一個簡單的鎖。

threading 模組提供的其他方法:

  • threading.currentThread(): 返回當前的執行緒變數。
  • threading.enumerate(): 返回一個包含正在執行的執行緒的list。正在執行指執行緒啟動後、結束前,不包括啟動前和終止後的執行緒。
  • threading.activeCount(): 返回正在執行的執行緒數量,與len(threading.enumerate())有相同的結果。

除了使用方法外,執行緒模組同樣提供了Thread類來處理執行緒,Thread類提供了以下方法:

  • run(): 用以表示執行緒活動的方法。
  • start():啟動執行緒活動。

     

  • join([time]): 等待至執行緒中止。這阻塞呼叫執行緒直至執行緒的join() 方法被呼叫中止-正常退出或者丟擲未處理的異常-或者是可選的超時發生。
  • isAlive(): 返回執行緒是否活動的。
  • getName(): 返回執行緒名。
  • setName(): 設定執行緒名。
# !/usr/bin/python
# -*- coding: UTF-8 -*-

import threading
import time

exitFlag = 0

class myThread(threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):
        print 'Starting' + self.name
        print_time(self.name,self.counter,5)
        print 'Exiting' + self.name

def print_time(threadName,delay,counter):
    while counter:
        if exitFlag:
            (threading.Thread).exit()
        time.sleep(delay)
        print '%s : %s' %(threadName,time.ctime(time.time()))
        counter -= 1

threading1 = myThread(1,'Thread-1',1)
threading2 = myThread(2,'Thread-2',2)

threading1.start()
threading2.start()

print 'Exiting Main Thread'

執行緒優先順序佇列( Queue)

Python的Queue模組中提供了同步的、執行緒安全的佇列類,包括FIFO(先入先出)佇列Queue,LIFO(後入先出)佇列LifoQueue,和優先順序佇列PriorityQueue。這些佇列都實現了鎖原語,能夠在多執行緒中直接使用。可以使用佇列來實現執行緒間的同步。

Queue模組中的常用方法:

 

  • Queue.qsize() 返回佇列的大小
  • Queue.empty() 如果佇列為空,返回True,反之False
  • Queue.full() 如果佇列滿了,返回True,反之False
  • Queue.full 與 maxsize 大小對應
  • Queue.get([block[, timeout]])獲取佇列,timeout等待時間
  • Queue.get_nowait() 相當Queue.get(False)
  • Queue.put(item) 寫入佇列,timeout等待時間
  • Queue.put_nowait(item) 相當Queue.put(item, False)
  • Queue.task_done() 在完成一項工作之後,Queue.task_done()函式向任務已經完成的佇列傳送一個訊號
  • Queue.join() 實際上意味著等到佇列為空,再執行別的操作
# !/usr/bin/python
# -*- coding: UTF-8 -*-
import Queue
import threading
import time

exitFlag = 0

class myThread(threading.Thread):
    def __init__(self,threadID,name,q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
    def run(self):
        print 'Starting' + self.name
        process_data(self.name,self.q)
        print 'Exiting' + self.name

def process_data(threadName,q):
    while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print '%s processing %s' % (threadName,data)
        else:
            queueLock.release()
        time.sleep(1)

threadList = ['Thread-1','Thread-2','Thread-3']
nameList = ['One','Two','Three','Four','Five']
queueLock = threading.Lock()
workQueue = Queue.Queue(10)
threads = []
threadID = 1

#建立執行緒
for tname in threadList:
    thread = myThread(threadID,tname,workQueue)
    thread.start()
    threads.append(thread)
    threadID += 1

#填充佇列
queueLock.acquire()
for word in nameList:
    workQueue.put(word)
queueLock.release()

#等待佇列清空
while not workQueue.empty():
    pass

#通知執行緒是時候退出
exitFlag = 1

#等待所有執行緒完成
for t in threads:
    t.join()
print 'Exiting Main Thread'