python併發_線程

来源:https://www.cnblogs.com/frx9527/archive/2018/12/10/thread.html
-Advertisement-
Play Games

關於進程的複習: 線程: Threading模塊的其它方法: 守護線程 線程鎖: 互斥鎖 遞歸鎖 ...


關於進程的複習:

# 管道
# 數據的共用 Manager dict list
# 進程池
    # cpu個數+1
    # ret = map(func,iterable)
        # 非同步 自帶close和join
        # 所有結果的[]
    # apply
        # 同步的:只有當func執行完之後,才會繼續向下執行其他代碼
        # ret = apply(func,args=())
        # 返回值就是func的return
    # apply_async
        # 非同步的:當func被註冊進入一個進程之後,程式就繼續向下執行
        # apply_async(func,args=())
        # 返回值 : apply_async返回的對象obj
        #          為了用戶能從中獲取func的返回值obj.get()
        # get會阻塞直到對應的func執行完畢拿到結果
        # 使用apply_async給進程池分配任務,
        # 需要先close後join來保持多進程和主進程代碼的同步性
# 回調函數是在主進程中執行的
from multiprocessing import Pool
def func1(n):
    return n+1

def func2(m):
    print(m)

if __name__ == '__main__':
    p = Pool(5)
    for i in  range(10,20):
        p.apply_async(func1,args=(i,),callback=func2)
    p.close()
    p.join()
import requests
from urllib.request import urlopen
from multiprocessing import Pool

## 爬取位元組數的例子:

def get(url):
    response = requests.get(url)
    if response.status_code == 200:
        return url,response.content.decode('utf-8')

# def get_urllib(url):
#     ret = urlopen(url)
#     return ret.read().decode('utf-8')

def call_back(args):
    url,content = args
    print(url,len(content))

if __name__ == '__main__':
    url_lst = [
        'https://www.cnblogs.com/',
        'http://www.baidu.com',
        'https://www.sogou.com/',
        'http://www.sohu.com/',
    ]
    p = Pool(5)
    for url in url_lst:
        p.apply_async(get,args=(url,),callback=call_back)
    p.close()
    p.join()

 

線程:

import os
import time
from threading import Thread


## 多線程併發
# def func(a, b):
#     n = a + b
#     print(n, os.getpid())  # 都在一個進程中
#
# print('主線程', os.getpid())  # 都在一個進程中
#
# for i in range(10):
#     t = Thread(target=func, args=(i, 6))
#     t.start()


## 同一進程中的各個線程,都可以共用該進程所擁有的資源
# def func(a,b):
#     global g
#     g = 0
#     print(g,os.getpid())
#
# g = 100
# t_lst = []
# for i in range(10):
#     t = Thread(target=func,args=(i,5))
#     t.start()
#     t_lst.append(t)
# for t in  t_lst : t.join()
# print(g)


## 繼承 類 實現
# class MyThread(Thread):
#     # 重寫初始化方法
#     def __init__(self,arg):
#         super().__init__()
#         self.arg = arg
#
#     def run(self):
#         time.sleep(1)
#         print(':::',self.arg)
#
# t = MyThread(10)
# t.start()


# class Sayhi(Thread):
#     def __init__(self,name):
#         super().__init__()
#         self.name=name
#
#     def run(self):
#         time.sleep(1)
#         print('%s say hello' % self.name)
#
# if __name__ == '__main__':
#     t = Sayhi('egon')
#     t.start()
#     print('主線程')



# https://www.cnblogs.com/Eva-J/articles/8306047.html
# 進程 是 最小的 記憶體分配單位
# 線程 是 操作系統調度的最小單位
# 線程直接被CPU執行,進程內至少含有一個線程,也可以開啟多個線程
    # 開啟一個線程所需要的時間要遠遠小於開啟一個進程
    # 多個線程內部有自己的數據棧,數據不共用
    # 全局變數在多個線程之間是共用的

# GIL鎖(即全局解釋器鎖)
# 在Cpython解釋器下的python程式 在同一時刻 多個線程中只能有一個線程被CPU執行
    # 高CPU : 計算類 --- 高CPU利用率
        # 如果真的需要高併發,可使用多進程,避免多線程GIL鎖
    # 高IO  : 一般程式都不會受GIL影響. 爬取網頁 200個網頁
        # qq聊天   send recv
        # 處理日誌文件 讀文件
        # 處理web請求
        # 讀資料庫 寫資料庫


import time
from threading import Thread
from multiprocessing import Process

def func(n):
    n + 1

if __name__ == '__main__':
    start = time.time()
    t_lst = []
    for i in range(100):
        t = Thread(target=func,args=(i,))
        t.start()
        t_lst.append(t)
    for t in t_lst:t.join()
    t1 = time.time() - start

## 證明線程比進程快的例子:

    start = time.time()
    t_lst = []
    for i in range(100):
        t = Process(target=func, args=(i,))
        t.start()
        t_lst.append(t)
    for t in t_lst: t.join()
    t2 = time.time() - start
    print(t1,t2)

 

Threading模塊的其它方法:

import time
import threading

## Thread實例對象的方法
  # isAlive(): 返回線程是否活動的。
  # getName(): 返回線程名。
  # setName(): 設置線程名。

def wahaha(n):
    time.sleep(0.5)
    print(n,threading.current_thread(),threading.get_ident())
    # print(threading.current_thread().getName())

for i in  range(10):
    threading.Thread(target=wahaha,args=(i,)).start()

# 返回正在運行的線程數量,與len(threading.enumerate())有相同的結果。
print(threading.active_count())    # 11
print(threading.current_thread())  # 返回當前的線程變數。

# 返回一個包含正在運行的線程的list。正在運行指線程啟動後、結束前,不包括啟動前和終止後的線程。
print(threading.enumerate())

## https://www.cnblogs.com/Eva-J/articles/8306047.html

 

守護線程

import time
from threading import Thread

def func1():
    while True:
        print('*'*10)
        time.sleep(1)

def func2():
    print('in func2')
    time.sleep(5)

t = Thread(target=func1,)
t.daemon = True
t.start()
t2 = Thread(target=func2,)
t2.start()
t2.join()  # 等待t2執行完畢
print('主線程')

# 守護進程隨著主進程代碼的執行結束而結束
# 守護線程會在主線程結束之後等待其他子線程的結束才結束

# 主進程在執行完自己的代碼之後不會立即結束 而是等待子進程結束之後 回收子進程的資源

#1 主進程在其代碼結束後就已經算運行完畢了(守護進程在此時就被回收),然後主進程會一直等非守護的子進程都運行完畢後回收子進程的資源(否則會產生僵屍進程),才會結束,
#2 主線程在其他非守護線程運行完畢後才算運行完畢(守護線程在此時就被回收)。因為主線程的結束意味著進程的結束,進程整體的資源都將被回收,
而進程必須保證非守護線程都運行完畢後才能結束。

 

線程鎖:  互斥鎖 遞歸鎖

import time
from threading import Lock,Thread

'''由於線程之間是進行隨機調度,並且每個線程可能只執行n條執行之後,當多個線程同時修改同一條數據時可能會出現臟數據,
   所以,出現了線程鎖 - 同一時刻允許一個線程執行操作。
'''

### Lock 互斥鎖 只有一把鑰匙
# def func(lock):
#     global n
#     lock.acquire()  # 加鎖
#     temp = n
#     time.sleep(0.2)
#     n = temp - 1
#     lock.release()
#
# n = 10
# t_lst = []
# lock = Lock()
# for i in range(10):lkqi
#     t = Thread(target=func,args=(lock,))  # 線程鎖
#     t.start()
#     t_lst.append(t)
#
# for t in t_lst: t.join()
# print(n)


### 科學家吃面 問題  造成死鎖
# noodle_lock  = Lock()
# fork_lock = Lock()
# def eat1(name):
#     noodle_lock.acquire()
#     print('%s拿到麵條啦'%name)
#     fork_lock.acquire()
#     print('%s拿到叉子了'%name)
#     print('%s吃面'%name)
#     fork_lock.release()
#     noodle_lock.release()
#
# def eat2(name):
#     fork_lock.acquire()
#     print('%s拿到叉子了'%name)
#     time.sleep(1)
#     noodle_lock.acquire()
#     print('%s拿到麵條啦'%name)
#     print('%s吃面'%name)
#     noodle_lock.release()
#     fork_lock.release()
#
# Thread(target=eat1,args=('alex',)).start()
# Thread(target=eat2,args=('Egon',)).start()
# Thread(target=eat1,args=('bossjin',)).start()
# Thread(target=eat2,args=('nezha',)).start()
## 當在同一個進程或線程中用到2把以上的鎖時,就容易產生死鎖。


from threading import RLock   # 遞歸鎖 可以多次使用 解決死鎖問題
fork_lock = noodle_lock  = RLock()   # 類似於一串上的兩把鑰匙
def eat1(name):
    noodle_lock.acquire()            # 一把鑰匙
    print('%s拿到麵條啦'%name)
    fork_lock.acquire()
    print('%s拿到叉子了'%name)
    print('%s吃面'%name)
    fork_lock.release()
    noodle_lock.release()  # 必須全部釋放之後,其它人才能用。

def eat2(name):
    fork_lock.acquire()
    print('%s拿到叉子了'%name)
    time.sleep(1)
    noodle_lock.acquire()
    print('%s拿到麵條啦'%name)
    print('%s吃面'%name)
    noodle_lock.release()
    fork_lock.release()

Thread(target=eat1,args=('alex',)).start()
Thread(target=eat2,args=('Egon',)).start()
Thread(target=eat1,args=('bossjin',)).start()
Thread(target=eat2,args=('nezha',)).start()

 

線程的信號量:

# import time
# from threading import Semaphore,Thread
# def func(sem,a,b):
#     sem.acquire()
#     time.sleep(1)
#     print(a+b)
#     sem.release()
#
# sem = Semaphore(4)
# for i in range(10):
#     t = Thread(target=func,args=(sem,i,i+5))
#     t.start()


'''互斥鎖 同時只允許一個線程更改數據,而Semaphore是同時允許一定數量的線程更改數據 ,
   比如廁所有3個坑,那最多只允許3個人上廁所,後面的人只能等裡面有人出來了才能再進去。
'''

import threading, time

def run(n):
    semaphore.acquire()
    time.sleep(1)
    print("run the thread: %s" % n)
    semaphore.release()

if __name__ == '__main__':
    num = 0
    semaphore = threading.BoundedSemaphore(3)  # 最多允許5個線程同時運行
    for i in range(12):
        t = threading.Thread(target=run, args=(i,))
        t.start()

 

線程的事件:

# !/usr/bin/env python
# -*- coding:utf-8 -*-

'''線程的事件用於主線程式控制制其他線程的執行,事件主要提供了三個方法 set、wait、clear。
事件處理的機制:全局定義了一個“Flag”,如果“Flag”值為 False,那麼當程式執行 event.wait 方法時就會阻塞,
如果“Flag”值為True,那麼event.wait 方法時便不再阻塞。
'''

import threading

def do(event):
    print('start.')
    event.wait()
    print('execute')

event_obj = threading.Event()  # 預設False
for i in range(6):
    t = threading.Thread(target=do,args=(event_obj,))
    t.start()

event_obj.clear()   # 設為False
input2 = input('>>>')
if input2 == 'true':
    event_obj.set()  # 設為 True


# 事件被創建的時候
# False狀態
    # wait() 阻塞
# True狀態
    # wait() 非阻塞
# clear 設置狀態為False
# set  設置狀態為True

 

定時器 Timer

import time
from threading import Timer
def func():
    print('時間同步')   #1-3

while True:
    t = Timer(5,func).start()   # 非阻塞的 5秒之後開始
    time.sleep(2)

# 定時器,指定n秒後執行某操作

 

更多內容,參考:http://www.cnblogs.com/wupeiqi/articles/5040827.html

 

線程隊列:

import queue

# 線程的隊列,內置了鎖,保證數據安全

# q = queue.Queue()  # 隊列 先進先出
# q.put(123)
# print(q.get())
# q.put_nowait(456)
# print(q.get_nowait())

# q = queue.LifoQueue()  # 棧 先進後出
# q.put(1)
# q.put(2)
# q.put(3)
# print(q.get())
# print(q.get())

q = queue.PriorityQueue()  # 優先順序隊列
q.put((20,'a'))
q.put((10,'b'))
q.put((30,'c'))
q.put((-5,'f'))
q.put((-5,'d'))
q.put((1,'?'))
print(q.get())   # 數字越小,優先順序越高 按ascii碼順序

 

線程池:https://www.cnblogs.com/Eva-J/articles/8306047.html#_label17


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

-Advertisement-
Play Games
更多相關文章
  • pom.xml(對Kaptcha.jar的引用) spring-mvc.xml(Kaptche的相關設置) BaseController.java(驗證碼獲取Controller) 前臺js(初始化驗證碼圖片) 當寫完前臺代碼,訪問login.jsp時驗證碼獲取失敗(Status Code:302 ...
  • java基礎之XML 1. XML解析概述 2. DOM4J介紹 2.1 常用包 2.2 內置元素 2.2 Element類 2.3 Attribute類 2.4 常用操作 3. 代碼演示 3.1 DOM4J讀取xml文件 3.2 DOM4J創建xml文件 3.2 DOM4J修改xml文件 ...
  • 在前面,我用了3篇文章解釋python的面向對象: 1. "面向對象:從代碼復用開始" 2. "面向對象:設置對象屬性" 3. "類和對象的名稱空間" 本篇是第4篇,用一個完整的示例來解釋面向對象的一些細節。 例子的模型是父類Employe和子類Manager,從類的定義開始,一步步完善直到類變得完 ...
  • 前面介紹了字元串變數的四種賦值方式,對於簡單的賦值來說完全夠用了,即便是兩個字元串拼接,也只需通過加號把兩個目標串連起來即可。但對於複雜的賦值來說就麻煩了,假設現在需要拼接一個很長的字元串,字元串內部包含了各種類型的變數,有整型,有雙精度型,有布爾型,有字元型,中間還夾雜著一些起粘合作用的子串,如此 ...
  • 當我們在python中需要列印出特定格式的內容時可以用到這個方法,方法介紹如下: 例如我們現在要收集用戶的一些個人信息,這時候我們的代碼如下: name=input("name: ")age=int(input("age: "))job=input("job: ")salary=input('sal ...
  • 第一類對象 函數名 == 變數名 函數對象可以像變數一樣進行賦值 還可以作為列表的元素進行使用 可以作為返回值返回 def wrapper(): def inner(): print("哈哈哈") return inner # 函數名可以像返回值一樣返回 ret = wrapper() ret() ...
  • 動態傳參 (重點) * ** 形參 * args在形參位置, *表示不定參數--接受的是位置參數 接受到的位置參數的動態傳參: 都是元組 形參的順序: 位置 *args 預設值 **kwargs 以後寫參數,可以隨意的進行搭配 def chi(zhushi, cai, fushi, tang, ti ...
  • client: socket connect send encode recv decode close server: socket bind listen 1.主動轉換成被動 2.向系統申請隊列(5) accept 1.阻塞等待客戶端的鏈接 2.創建一個新的socket(主動) recv sen ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...