2018-08-08 day18 多線程

進(jìn)程和線程

1.什么是進(jìn)程

  • 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個應(yīng)用程序
  • 每個進(jìn)程之間是獨(dú)立的,每個進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空間內(nèi)

2.什么是線程

  • 一個進(jìn)程想要執(zhí)行任務(wù),必須有線程(每個進(jìn)程至少要有1條線程)
  • 一個進(jìn)程(程序)的所有任務(wù)都在線程中執(zhí)行

3.什么是多線程

  • 1個進(jìn)程中可以開啟多條線程,每條線程可以并行執(zhí)行不同的任務(wù)
  • 多線程技術(shù)可以提高程序的執(zhí)行效率

4.多線程的原理

  • 同一個時間,CPU只能處理一條線程,只有1條線程在執(zhí)行
  • 多線程并發(fā)執(zhí)行,其實(shí)是cpu快速的在多條線程之間調(diào)度
  • 如果CPU調(diào)度線程的事件足夠快,就造成了多線程并發(fā)執(zhí)行的假象

耗時操作

1.耗時操作放到主線程中的問題

  • 耗時操作放到主線程中會阻塞線程
  • 多個耗時操作都放到一個線程中執(zhí)行,最終執(zhí)行時間是多個耗時操作時間和

2.怎么解決

  • 使用多線程(創(chuàng)建多個線程)

多線程技術(shù)

  • python內(nèi)置的threading模塊,可以支持多線程

  • 所有的進(jìn)程默認(rèn)都有一個線程(一般叫這個線程為主線程),其他的線程叫子線

  • 如果想要在進(jìn)程中添加其他的線程,就創(chuàng)建線程對象

import threading
import time


def download(file):
    print('開始下載', file)
    time.sleep(3)
    print(file, '下載結(jié)束')


if __name__ == '__main__':
    print('aaaa')
    # 1.創(chuàng)建線程對象
    
    target:需要在子線程中執(zhí)行的函數(shù)
    args:調(diào)用函數(shù)的實(shí)參列表(參數(shù)類型必須是列表)
    
    t1 = threading.Thread(target=download, args=['愛情公寓'])
    # 2.在子線程中執(zhí)行任務(wù)
    t1.start()
    t2 = threading.Thread(target=download, args=['allalala'])
    t2.start()
    print('66666666666')
    time.sleep(5)
  • 方式2:寫一個自己的線程類
  1. 寫一個類,繼承Thread類
  2. 重寫run方法,在里面規(guī)定需要在子線程中執(zhí)行的任務(wù)
  3. 在子線程中執(zhí)行的任務(wù)對應(yīng)的功能,如果需要參數(shù),通過對象屬性來傳值

傳值使用對象屬性來傳值

from threading import Thread
from requests import request
import os
import re


# 下載數(shù)據(jù)
class DownloadThread(Thread):
    '''下載類'''

    def __init__(self, file):
        super().__init__()
        self.file = file

    def run(self):
        '''run方法'''
        '''
        寫在這個方法的內(nèi)容就是在子線程中執(zhí)行的內(nèi)容
        這個方法不要直接調(diào)用
        '''
        print('開始下載')
        suffix = re.search(r'[%\\]\w+\.\w+$', self.file).group()
        response = request('GET', self.file)
        data = response.content
        with open('./day02-多線程/' + suffix, 'wb') as f:
            f.write(data)
        print('下載完成....')


if __name__ == '__main__':
    print(os.getcwd())
    d1 = DownloadThread(
        'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533720058151&di=766b5c97653351e805c85881ecaa57d0&imgtype=0&src=http%3A%2F%2Fx.itunes123.com%2Fuploadfiles%2Fb2ab55461e6dc7a82895c7425fc89017.jpg'
    )
    # 通過start間接調(diào)用run方法,run方法中的任務(wù)在子線程中執(zhí)行
    d1.start()
    # 直接調(diào)用run方法,run方法在當(dāng)前線程中執(zhí)行
    print('哇哈哈哈哈哈哈')

多線程的應(yīng)用

import socket
from threading import Thread


class MsgThread(Thread):
    '''在子線程中處理不同的客戶端會話'''

    def __init__(self, conver: socket.socket, addr):
        # 形參接受時,參數(shù)后面加:進(jìn)行類型說明
        # 注意只是說明類型而不是轉(zhuǎn)換類型
        super().__init__()
        self.conver = conver
        self.addr = addr

    def run(self):
        while True:
            self.conver.send('哇哈哈哈'.encode())
            print(self.addr, self.conver.recv(1024).decode(encoding='utf-8'))


if __name__ == '__main__':
    server = socket.socket()
    server.bind(('10.7.181.92', 8080))
    server.listen(5)
    while True:
        conver, addr = server.accept()
        c = MsgThread(conver, addr)
        c.start()
        # while True:
        # conver.send('666'.encode())
        # print(conver.recv(1024).decode(encoding='utf-8'))

join方法

  • 獲取當(dāng)前線程
  • 主線程:MainThread
  • 子線程:Thread-數(shù)字
currentThread()
  • 如果一個任務(wù)想要在另一個子線程結(jié)束后再執(zhí)行,就用這個子線程對象調(diào)用join
  • 所以join也會阻塞線程,阻塞到子線程任務(wù)執(zhí)行完成為止
from threading import Thread, currentThread
from random import randint
import time


class Download(Thread):
    def __init__(self, file):
        super().__init__()  # 必須調(diào)用,否則當(dāng)前這個類對象就不是線程
        self.file = file

    def run(self):
        print('開始下載', self.file)
        time.sleep(randint(3, 7))
        print(currentThread())
        print('下載完成', self.file)


if __name__ == '__main__':
    # time.time():獲取當(dāng)前的時間戳
    start_time = time.time()
    t1 = Download('狗屎')
    t1.start()

    t2 = Download('紅糖')
    t2.start()
    print('.............')
    # 獲取當(dāng)前線程
    '''
    主線程:MainThread
    子線程:Thread-數(shù)字
    '''
    print(currentThread())
    # 如果一個任務(wù)想要在另一個子線程結(jié)束后再執(zhí)行,就用這個子線程對象調(diào)用join
    # 所以join也會阻塞線程,阻塞到子線程任務(wù)執(zhí)行完成為止
    t1.join()
    end_time = time.time()
    print('耗時%.2f' % (end_time - start_time))
    t2.join()
    end_time = time.time()
    print('總共耗時%.2f' % (end_time - start_time))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容