參考博客
https://www.cnblogs.com/whatisfantasy/p/6440585.html
1 概念梳理:
1.1 線程
1.1.1 什麼是線程
線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。一個線程是一個execution context(執行上下文),即一個cpu執行時所需要的一串指令。
1.1.2 線程的工作方式
假設你正在讀一本書,沒有讀完,你想休息一下,但是你想在回來時恢復到當時讀的具體進度。有一個方法就是記下頁數、行數與字數這三個數值,這些數值就是execution context。如果你的室友在你休息的時候,使用相同的方法讀這本書。你和她只需要這三個數字記下來就可以在交替的時間共同閱讀這本書了。
線程的工作方式與此類似。CPU會給你一個在同一時間能夠做多個運算的幻覺,實際上它在每個運算上只花了極少的時間,本質上CPU同一時刻只幹了一件事。它能這樣做就是因爲它有每個運算的execution context。就像你能夠和你朋友共享同一本書一樣,多任務也能共享同一塊CPU。
1.2 進程
一個程序的執行實例就是一個進程。每一個進程提供執行程序所需的所有資源。(進程本質上是資源的集合)
一個進程有一個虛擬的地址空間、可執行的代碼、操作系統的接口、安全的上下文(記錄啓動該進程的用戶和權限等等)、唯一的進程ID、環境變量、優先級類、最小和最大的工作空間(內存空間),還要有至少一個線程。
每一個進程啓動時都會最先產生一個線程,即主線程。然後主線程會再創建其他的子線程。
1.3 進程與線程區別
1.同一個進程中的線程共享同一內存空間,但是進程之間是獨立的。
2.同一個進程中的所有線程的數據是共享的(進程通訊),進程之間的數據是獨立的。
3.對主線程的修改可能會影響其他線程的行爲,但是父進程的修改(除了刪除以外)不會影響其他子進程。
4.線程是一個上下文的執行指令,而進程則是與運算相關的一簇資源。
5.同一個進程的線程之間可以直接通信,但是進程之間的交流需要藉助中間代理來實現。
6.創建新的線程很容易,但是創建新的進程需要對父進程做一次複製。
7.一個線程可以操作同一進程的其他線程,但是進程只能操作其子進程。
8.線程啓動速度快,進程啓動速度慢(但是兩者運行速度沒有可比性)。
2 多線程
2.1 線程常用方法
2.1.1 Thread類
1.普通創建方式
import threading
import time
def run(n):
print("task", n)
time.sleep(1)
print('2s')
time.sleep(1)
print('1s')
time.sleep(1)
print('0s')
time.sleep(1)
t1 = threading.Thread(target=run, args=("t1",))
t2 = threading.Thread(target=run, args=("t2",))
t1.start()
t2.start()
"""
task t1
task t2
2s
2s
1s
1s
0s
0s
"""
2.繼承threading.Thread來自定義線程類
其本質是重構Thread類中的run方法
import threading
import time
class MyThread(threading.Thread):
def __init__(self, n):
super(MyThread, self).__init__() # 重構run函數必須要寫
self.n = n
def run(self):
print("task", self.n)
time.sleep(1)
print('2s')
time.sleep(1)
print('1s')
time.sleep(1)
print('0s')
time.sleep(1)
if __name__ == "__main__":
t1 = MyThread("t1")
t2 = MyThread("t2")
t1.start()
t2.start()
多線程實例
# -- coding: utf-8 --
import cv2
import numpy as np
#引入多線程模塊
import threading
i=1
t_lock=threading.Lock()
class read_frame(threading.Thread):
def __init__(self,cap):
threading.Thread.__init__(self)
self.cap = cap
def run(self):
global ret,frame
while ret:
t_lock.acquire()
ret,frame=self.cap.read()
global i
print("1_thred number is {}".format(i + 2))
cv2.imshow("display",frame)
t_lock.release()
if cv2.waitKey(1)==ord("q"):
break;
class detect_frame(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global frame
while ret:
global i
t_lock.acquire()
cv2.putText(frame,"hello",(40,40),cv2.FONT_HERSHEY_SIMPLEX,4,(127,127,255),2)
cv2.imshow("2_threading",frame)
print("2_thred number is {}".format(i-1))
t_lock.release()
if cv2.waitKey(1) == ord("q"):
break
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
read_frame_threaing=read_frame(cap)
read_frame_threaing.start()
putText_threading=detect_frame()
putText_threading.start()
read_frame_threaing.join()
putText_threading.join()
多進程
# -- coding: utf-8 --
import cv2
from threading import Thread
from multiprocessing import Process,Manager
import time
from queue import LifoQueue
import configparser
#採用兩個進程同時獲得微波與攝像頭的數據,攝像頭採用兩個線程,一個線程讀取,另一個線程保存數據。
def get_video(file_name,dic):
q = LifoQueue()
def get_frames(q):
cap = cv2.VideoCapture("video3.MKV")
while cap.isOpened():
t1 = time.time()
ret, frame = cap.read()
t2 = time.time()
if ret:
q.put((frame, (t1 + t2) / 2.))
#if dic['end']==False:
# break
else:
print('Camera cannot open.')
q.put(([], ''))
cap.release()
def save_frames(q):
file_name = './1.mp4'
f = open(file_name + '_video.log', 'w')
video_frame_id = 1
total = float(1) * 60 * 15
fourcc = cv2.VideoWriter_fourcc(*"MJPG")
writer = cv2.VideoWriter(file_name + '.avi', fourcc, 15, (640,480))
while True:
ts = time.time()
frame, t = q.get()
frame = cv2.resize(frame, (640,480))
cv2.imshow("test",frame)
q.queue.clear()
msg = '{:d},{:.9f}\n'.format(video_frame_id, t)
writer.write(frame)
f.write(msg)
video_frame_id += 1
if video_frame_id > total:
dic['end'] = True
break
te = time.time()
cv2.waitKey(1)
time.sleep(max(0.001, 1. / 15 + ts - te))
writer.release()
f.close()
t1 = Thread(target=get_frames, args=(q, ))
t2 = Thread(target=save_frames, args=(q, ))
t1.start()
t2.start()
t1.join()
t2.join()
def processing_video():
while 1:
print("hello")
if __name__ == '__main__':
with Manager() as manager:
dic=manager.dict()
#生成一個進程間的共享字典
dic['end']=False
dic['exit']=False
while True:
key_down=cv2.waitKey(1)
p1 = Process(target=processing_video)
p1.start()
if key_down==ord('q'):
dic['end']=True
dic['exit']=True
p2 = Process(
target=get_video,
args=(dic))
p2.start()
p2.join()
p1.join()