Python程序中的線程操作-創建多線程


Python程序中的線程操作-創建多線程

一、Python線程模塊的選擇

Python提供了幾個用於多線程的編程的模塊,包括thread、threading和Queue等。thread和threading模塊允許程序員創建和管理線程。thread模塊提供了基本的線程和鎖的支持,threading提供了更高級別、功能更強大的線程管理的功能。Queue模塊允許用戶創建一個可以用於多個線程之間共享輸一局的隊列數據結構。

避免使用thread模塊,因為更高級別的threading模塊更為先進,對線程的支持更為完善,而且使用thread模塊里的屬性有可能會與threading出現沖突;其次低級別的thread模塊的同步原語很少(實際上只有一個),而threading模塊則有很多;再者,thread模塊中當主線程結束時,所有的線程都會被強制結束掉,沒有警告也不會有正常的清除工作,至少threading模塊能確保重要的子線程退出后進程才退出。

thread模塊不支持守護線程,當主線程退出時,所有的子線程不論它們是否還在工作,都會被強行退出。而threading模塊支持守護線程,守護線程一般是一個等待客戶請求的服務器,如果沒有客戶提出請求它就在那等着,如果設定一個線程為守護線程,就表示這個線程是不重要的,在進程退出的時候,不用等待這個線程退出。

二、threading模塊

multiprocess模塊的完全模仿了threading模塊的接口,二者在使用層面,有很大的相似性,因而不再詳細介紹(官方鏈接)

三、通過threading.Thread類創建線程

3.1創建線程的方式一

from threading import Thread
import time
def sayhi(name):
    time.sleep(2)
    print('%s say hello' %name)
    
# t = Thread(target=sayhi, args=('nick',))
# t.start()
# print('主線程')
if __name__ == '__main__':
    t=Thread(target=sayhi,args=('nick',))
    t.start()
    print('主線程')

3.2創建線程的方式二

from threading import Thread
import time
class Sayhi(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        time.sleep(2)
        print('%s say hello' % self.name)


if __name__ == '__main__':
    t = Sayhi('nick')
    t.start()
    print('主線程')

四、多線程與多進程

4.1pid的比較

from threading import Thread
from multiprocessing import Process
import os


def work():
    print('hello', os.getpid())


if __name__ == '__main__':
    # part1:在主進程下開啟多個線程,每個線程都跟主進程的pid一樣
    t1 = Thread(target=work)
    t2 = Thread(target=work)
    t1.start()
    t2.start()
    print('主線程/主進程pid', os.getpid())

    # part2:開多個進程,每個進程都有不同的pid
    p1 = Process(target=work)
    p2 = Process(target=work)
    p1.start()
    p2.start()
    print('主線程/主進程pid', os.getpid())

4.2開啟效率的較量

from threading import Thread
from multiprocessing import Process
import os

def work():
    print('hello')

if __name__ == '__main__':
    # 在主進程下開啟線程
    t=Thread(target=work)
    t.start()
    print('主線程/主進程')
    '''
    打印結果:
    hello
    主線程/主進程
    '''

    # 在主進程下開啟子進程
    t=Process(target=work)
    t.start()
    print('主線程/主進程')
    '''
    打印結果:
    主線程/主進程
    hello
    '''

4.3內存數據的共享問題

from threading import Thread
from multiprocessing import Process
import os


def work():
    global n
    n = 0


if __name__ == '__main__':
    # n=100
    # p=Process(target=work)
    # p.start()
    # p.join()
    # print('主',n) # 毫無疑問子進程p已經將自己的全局的n改成了0,但改的僅僅是它自己的,查看父進程的n仍然為100

    n = 1
    t = Thread(target=work)
    t.start()
    t.join()
    print('主', n)  # 查看結果為0,因為同一進程內的線程之間共享進程內的數據

五、Thread類的其他方法

Thread實例對象的方法:

  • isAlive():返回線程是否活動的。
  • getName():返回線程名。
  • setName():設置線程名。

threading模塊提供的一些方法:

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

5.1代碼示例

from threading import Thread
import threading
from multiprocessing import Process
import os


def work():
    import time
    time.sleep(3)
    print(threading.current_thread().getName())


if __name__ == '__main__':
    # 在主進程下開啟線程
    t = Thread(target=work)
    t.start()

    print(threading.current_thread().getName())
    print(threading.current_thread())  # 主線程
    print(threading.enumerate())  # 連同主線程在內有兩個運行的線程
    print(threading.active_count())
    print('主線程/主進程')

    '''
    打印結果:
    MainThread
    <_MainThread(MainThread, started 140735268892672)>
    [<_MainThread(MainThread, started 140735268892672)>, <Thread(Thread-1, started 123145307557888)>]
    主線程/主進程
    Thread-1
    '''

5.2join方法

from threading import Thread
import time


def sayhi(name):
    time.sleep(2)
    print('%s say hello' % name)


if __name__ == '__main__':
    t = Thread(target=sayhi, args=('nick',))
    t.start()
    t.join() #主線程等待子線程結束
    print('主線程')
    print(t.is_alive())
    '''
    nick say hello
    主線程
    False
    '''

六、多線程實現socket

6.1服務端

import multiprocessing
import threading

import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('127.0.0.1',8080))
s.listen(5)

def action(conn):
    while True:
        data=conn.recv(1024)
        print(data)
        conn.send(data.upper())

if __name__ == '__main__':

    while True:
        conn,addr=s.accept()


        p=threading.Thread(target=action,args=(conn,))
        p.start()

6.2客戶端

import socket

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1',8080))

while True:
    msg=input('>>: ').strip()
    if not msg:continue

    s.send(msg.encode('utf-8'))
    data=s.recv(1024)
    print(data)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM