亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Python核心技術與實戰 筆記

系統 1660 0

基礎篇

Python核心技術與實戰 筆記_第1張圖片

Jupyter Notebook

優點

  • 整合所有的資源
  • 交互性編程體驗
  • 零成本重現結果

實踐站點

  • Jupyter 官方
  • Google Research 提供的 Colab 環境
  • 安裝
  • 運行

列表與元組

列表和元組,都是 一個可以放置任意數據類型的有序集合

          
            l = [1, 2, 'hello', 'world'] # 列表中同時含有 int 和 string 類型的元素
l
[1, 2, 'hello', 'world']

tup = ('jason', 22) # 元組中同時含有 int 和 string 類型的元素
tup
('jason', 22)
          
        
  • 列表是動態的,長度大小不固定,可以隨意地增加、刪減或者改變元素 (mutable)
  • 元組是靜態的,場地大小固定,無法增加刪除或者改變 (immutable)
  • 都支持負數索引;
  • 都支持切片操作;
  • 都可以隨意嵌套;
  • 兩者可以通過 list() tuple() 函數相互轉換;

列表和元組存儲方式的差異

由于列表是動態的,所以它需要存儲指針,來指向對應的元素。增加/刪除的時間復雜度均為 O(1)。

          
            l = []
l.__sizeof__() // 空列表的存儲空間為 40 字節
40
l.append(1)
l.__sizeof__()
72 // 加入了元素 1 之后,列表為其分配了可以存儲 4 個元素的空間 (72 - 40)/8 = 4
l.append(2)
l.__sizeof__()
72 // 由于之前分配了空間,所以加入元素 2,列表空間不變
l.append(3)
l.__sizeof__()
72 // 同上
l.append(4)
l.__sizeof__()
72 // 同上
l.append(5)
l.__sizeof__()
104 // 加入元素 5 之后,列表的空間不足,所以又額外分配了可以存儲 4 個元素的空間
          
        

使用場景

  • 如果存儲的數據和數量不變,那么肯定選用元組更合適
  • 如果存儲的數據和數量是可變的,那么則用列表更合適

區別

  • 列表是動態的,長度可變,可以隨意的增加、刪除或者改變元素;列表的存儲空間略大于元組,性能略遜于元組;
  • 元組是靜態的,長度大小固定,不可對元素進行增加、刪除、修改操作,元組相對于列表更加的輕量級、性能稍優;

思考題

          
            # 創建空列表
# option A:list()是一個function call,Python的function call會創建stack,并且進行一系列參數檢查的操作,比較expensive
empty_list = list()

# option B:[]是一個內置的C函數,可以直接被調用,因此效率高
empty_list = []
          
        

字典與集合

字典是一系列無序元素的組合,其長度大小可變,元素可以任意的刪除和改變,相比于列表和元組,字典的性能更優,特別是對于查找、添加和刪除操作,字典都能在常數時間復雜度內完成。而集合和字典基本相同,唯一的區別,就是集合沒有件和值的配對,是一系列無序的、唯一的元素組合。

          
            # 定義字典
d = {'name': 'jason', 'age': 20}
# 增加元素對'gender': 'male'
d['gender'] = 'male' 
# 增加元素對'dob': '1999-02-01'
d['dob'] = '1999-02-01' 
d
{'name': 'jason', 'age': 20, 'gender': 'male', 'dob': '1999-02-01'}
# 更新鍵'dob'對應的值 
d['dob'] = '1998-01-01' 
# 刪除鍵為'dob'的元素對
d.pop('dob') 
'1998-01-01'
d
{'name': 'jason', 'age': 20, 'gender': 'male'}

# 定義集合
s = {1, 2, 3}
# 增加元素 4 到集合
s.add(4)
s
{1, 2, 3, 4}
# 從集合中刪除元素 4
s.remove(4) 
s
{1, 2, 3}


d = {'b': 1, 'a': 2, 'c': 10}
# 根據字典鍵的升序排序
d_sorted_by_key = sorted(d.items(), key=lambda x: x[0]) 
 # 根據字典值的升序排序
d_sorted_by_value = sorted(d.items(), key=lambda x: x[1])
          
        

可以使用 get(key,default) 函數來進行字典索引。如果鍵不存在,調用該函數可以返回一個默認的值。

集合不支持索引操作,因為集合本質上是一個哈希表,和列表不一樣。

字典和集合性能

字典和集合是進行性能高度優化的數據結構,特別是對于查找、添加和刪除操作。

字典和集合的工作原理

字典和集合的內部結構都是一張哈希表

  • 對于字典而言,這張哈希表存儲了哈希值,鍵和值這三個元素
  • 對于集合而言,區別就是哈希表內沒有鍵和值的配對,只有單一的元素了

插入操作

每次向字典或集合插入一個元素時,Python 會首先計算鍵的哈希值(hash(key)),再和 mask = PyDicMinSize - 1 做與操作,計算這個元素應該插入哈希表的位置 index = hash(key) & mask。如果哈希表中此位置是空的,那么這個元素就會被插入其中。而如果此位置已被占用,Python 便會比較兩個元素的哈希值和鍵是否相等。

  • 若兩者都相等,則表明這個元素已經存在,如果值不同,則更新值。
  • 若兩者中有一個不相等,這種情況我們通常稱為哈希沖突(hash collision),意思是兩個元素的鍵不相等,但是哈希值相等。這種情況下,Python 便會繼續尋找表中空余的位置,直到找到位置為止。

查找操作

先通過哈希值找到目標位置,然后比較哈希表這個位置中元素的哈希值和鍵,與需要查找的元素是否相等,如果相等,則直接返回,否則繼續查找,知道為空或拋出異常為止

刪除操作

暫時對這個位置得到元素賦予一個特殊的值,等到重新調整哈希表的大小時,再將其刪除。

字符串

  • Python 中字符串使用單引號、雙引號或三引號表示,三者意義相同,并沒有什么區別。其中,三引號的字符串通常用在多行字符串的場景。
  • Python 中字符串是不可變的(前面所講的新版本 Python 中拼接操作’+='是個例外)。因此,隨意改變字符串中字符的值,是不被允許的。
  • Python 新版本(2.5+)中,字符串的拼接變得比以前高效了許多,你可以放心使用。
  • Python 中字符串的格式化(string.format,f)常常用在輸出、日志的記錄等場景。

輸入與輸出

輸入輸出基礎

生產環境中使用強制轉換時,請記得加上 try except

文件輸入輸出

所有 I/O 都應該進行錯誤處理。因為 I/O 操作可能會有各種各樣的情況出現,而一個健壯(robust)的程序,需要能應對各種情況的發生,而不應該崩潰(故意設計的情況除外)。

JSON 序列化與實戰

  • json.dumps() 函數,接受 python 的基本數據類型,然后將其序列化為 string;
  • json.loads() 函數,接受一個合法字符串,然后將其序列化為 python 的基本數據類型;

條件與循環

  • 在條件語句中,if 可以單獨使用,但是 elif 和 else 必須和 if 同時搭配使用;而 If 條件語句的判斷,除了 boolean 類型外,其他的最好顯示出來。
  • 在 for 循環中,如果需要同時訪問索引和元素,你可以使用 enumerate() 函數來簡化代碼。
  • 寫條件與循環時,合理利用+continue+或者+break+來避免復雜的嵌套,是十分重要的。
  • 要注意條件與循環的復用,簡單功能往往可以用一行直接完成,極大地提高代碼質量與效率。

異常處理

  • 異常,通常是指程序運行的過程中遇到了錯誤,終止并退出。我們通常使用 try except 語句去處理異常,這樣程序就不會被終止,仍能繼續執行。
  • 處理異常時,如果有必須執行的語句,比如文件打開后必須關閉等等,則可以放在 finally block 中。
  • 異常處理,通常用在你不確定某段代碼能否成功執行,也無法輕易判斷的情況下,比如數據庫的連接、讀取等等。正常的 flow-control 邏輯,不要使用異常處理,直接用條件語句解決就可以了。

自定義函數

  • Python 中函數的參數可以接受任意的數據類型,使用起來需要注意,必要時請在函數開頭加入數據類型的檢查;
  • 和其他語言不同,Python 中函數的參數可以設定默認值;
  • 嵌套函數的使用,能保證數據的隱私性,提高程序運行效率;
  • 合理地使用閉包,則可以簡化程序的復雜度,提高可讀性;

匿名函數

優點:

  • 減少代碼的重復性;
  • 模塊化代碼;

map(function,iterable)

表示對 iterable 中的每個元素,都運用 function 這個函數,最后返回一個新的可遍歷的集合。

          
            def square(x):
    return x**2

squared = map(square, [1, 2, 3, 4, 5]) # [2, 4, 6, 8, 10]
          
        

filter(function,iterable)

表示對 iterable 中的每個元素,都使用 function 判斷,并返回 True 或者 False,最后將返回 True 的元素組成一個新的可遍歷的集合。

          
            l = [1, 2, 3, 4, 5]
new_list = filter(lambda x: x % 2 == 0, l) # [2, 4]
          
        

reduce(function,iterable)

規定它有兩個參數,表示對 iterable 中的每個元素以及上一次調用后的結果,運用 function 進行計算,所以最后返回的是一個單獨的數值。

          
            l = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, l) # 1*2*3*4*5 = 120
          
        

面向對象

基本概念

  • 類:一群有著相似性的事物的集合;
  • 對象:集合中的一個事物;
  • 屬性:對象的某個靜態特征;
  • 函數:對象某個動態能力

三要素:

  • 繼承
  • 封裝
  • 多態

模塊化編程

  • 通過絕對路徑和相對路徑,我們可以 import 模塊;
  • 在大型工程中模塊化非常重要,模塊的索引要通過絕對路徑來做,而絕對路徑從程序的根目錄開始;
  • 記著巧用 if __name__ == "__main__" 來避開 import 時執行;

進階篇

Python 對象的比較、拷貝

  • 比較操作符 == 表示比較對象間的值是否相等,而 is 表示比較對象的標識是否相等,即它們是否指向同一個內存地址。
  • 比較操作符 is 效率優于 == ,因為 is 操作符無法被重載,執行 is 操作只是簡單的獲取對象的 ID,并進行比較;而 == 操作符則會遞歸地遍歷對象的所有值,并逐一比較。
  • 淺拷貝中的元素,是原對象中子對象的引用,因此,如果原對象中的元素是可變的,改變其也會影響拷貝后的對象,存在一定的副作用。
  • 深度拷貝則會遞歸地拷貝原對象中的每一個子對象,因此拷貝后的對象和原對象互不相關。另外,深度拷貝中會維護一個字典,記錄已經拷貝的對象及其 ID,來提高效率并防止無限遞歸的發生。

值傳遞與引用傳遞

常見的參數傳遞有 2 種:

  • 值傳遞:通常就是拷貝對象的值,然后傳遞給函數里的新變量,原變量和新變量之間相互獨立,互不影響
  • 引用傳遞:通常是指把參數的引用傳給新的變量,這樣,原變量和新變量就會指向同一塊內存地址。

準確來說, python 的參數傳遞是 賦值傳遞 ,或者叫做對象的 引用傳遞 ,python 里所有的數據類型都是對象,所以參數傳遞時,只是讓新變量與原變量指向相同的對象而已,并不存在值傳遞或引用傳遞一說。

需要注意的是,這里的賦值或對象的引用傳遞,不是指一個具體的內存地址,二十指一個具體的對象。

  • 如果對象是可變的,當其改變時,所有指向這個對象的變量都會改變;
  • 如果對象不可變,簡單的賦值只能改變其中一個變量的值,其余變量則不受影響;

裝飾器

函數也是對象

          
            def func(message):
    print('Got a message: {}'.format(message))
    
send_message = func
send_message('hello world')

# 輸出
Got a message: hello world
          
        

函數可以作為函數參數

          
            def get_message(message):
    return 'Got a message: ' + message


def root_call(func, message):
    print(func(message))
    
root_call(get_message, 'hello world')

# 輸出
Got a message: hello world
          
        

函數可以嵌套函數

          
            def func(message):
    def get_message(message):
        print('Got a message: {}'.format(message))
    return get_message(message)

func('hello world')

# 輸出
Got a message: hello world
          
        

函數的返回值也可以是函數對象(閉包)

          
            def func_closure():
    def get_message(message):
        print('Got a message: {}'.format(message))
    return get_message

send_message = func_closure()
send_message('hello world')

# 輸出
Got a message: hello world
          
        

簡單使用裝飾器

          
            def my_decorator(func):
    def wrapper():
        print('wrapper of decorator')
        func()
    return wrapper

def greet():
    print('hello world')

greet = my_decorator(greet)
greet()

# 輸出
wrapper of decorator
hello world
          
        

更優雅的寫法

          
            def my_decorator(func):
    def wrapper():
        print('wrapper of decorator')
        func()
    return wrapper

@my_decorator
def greet():
    print('hello world')

greet()
          
        

帶參數的裝飾器

          
            def my_decorator(func):
    def wrapper(message):
        print('wrapper of decorator')
        func(message)
    return wrapper


@my_decorator
def greet(message):
    print(message)


greet('hello world')

# 輸出
wrapper of decorator
hello world
          
        

帶自定義參數的裝飾器

          
            def repeat(num):
    def my_decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(num):
                print('wrapper of decorator')
                func(*args, **kwargs)
        return wrapper
    return my_decorator


@repeat(4)
def greet(message):
    print(message)

greet('hello world')

# 輸出:
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world
          
        

上述 green() 函數被裝飾以后,它的元信息會發生改變,可勇敢 greet__name__ 來查看。可通過內置裝飾器來解決這個問題

          
            import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('wrapper of decorator')
        func(*args, **kwargs)
    return wrapper
    
@my_decorator
def greet(message):
    print(message)

greet.__name__

# 輸出
'greet'
          
        

類裝飾器

          
            class Count:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print('num of calls is: {}'.format(self.num_calls))
        return self.func(*args, **kwargs)

@Count
def example():
    print("hello world")

example()

# 輸出
num of calls is: 1
hello world

example()

# 輸出
num of calls is: 2
hello world
          
        

裝飾器支持嵌套使用

          
            @decorator1
@decorator2
@decorator3
def func():
    ...

# 等價于
decorator1(decorator2(decorator3(func)))
          
        

裝飾器使用場景:

  • 身份認證
  • 日志記錄
  • 輸入合理性檢查
  • 緩存(LRU cache)

metaclass

metaclass 是 Python 黑魔法級別的語言特性,它可以改變正常 Python 類型的創建過程。

  • 所有 Python 的用戶定義類,都是 type 這個類的實例
  • 用戶自定義類,只不過是 type 類的 __ call __ 運算符重載
  • metaclass 是 type 的子類,通過替換 type 的 __ call __ 運算符重載機制,超越變形正常的類
          
            class Mymeta(type):
    def __init__(self, name, bases, dic):
        super().__init__(name, bases, dic)
        print('===>Mymeta.__init__')
        print(self.__name__)
        print(dic)
        print(self.yaml_tag)

    def __new__(cls, *args, **kwargs):
        print('===>Mymeta.__new__')
        print(cls.__name__)
        return type.__new__(cls, *args, **kwargs)

    def __call__(cls, *args, **kwargs):
        print('===>Mymeta.__call__')
        obj = cls.__new__(cls)
        cls.__init__(cls, *args, **kwargs)
        return obj
    
class Foo(metaclass=Mymeta):
    yaml_tag = '!Foo'

    def __init__(self, name):
        print('Foo.__init__')
        self.name = name
 
    def __new__(cls, *args, **kwargs):
        print('Foo.__new__')
        return object.__new__(cls)

foo = Foo('foo')
          
        

迭代器和生成器

  • 容器時可迭代對象,可迭代對象調用 iter() 函數,可以得到一個迭代器。迭代器可以通過 next() 函數來得到下一個元素,從而支持遍歷
  • 生成器時一種特殊的迭代器,合理使用生成器,可以降低內存占用、優化程序結構、提高程序速度
  • 生成器在 Python 2 的版本上,是協程的一種重要實現方式;而 Python 3.5 引入的 async、await 語法糖,生成器實現協程的方式就已經落后了。

協程

協程是實現并發編程的一種方式

  • 協程和多線程的區別,主要在于兩點,一是協程為單線程;二是協程由用戶決定,在哪些地方交出控制權,切換到下一個任務
  • 協程的寫法更加簡潔清晰;把 async/await 語法和 create_task 結合起來用,對于中小級別的并發需求已經毫無壓力

生產者/消費者 模型

          
            import asyncio
import random

async def consumer(queue, id):
    while True:
        val = await queue.get()
        print('{} get a val: {}'.format(id, val))
        await asyncio.sleep(1)

async def producer(queue, id):
    for i in range(5):
        val = random.randint(1, 10)
        await queue.put(val)
        print('{} put a val: {}'.format(id, val))
        await asyncio.sleep(1)

async def main():
    queue = asyncio.Queue()

    consumer_1 = asyncio.create_task(consumer(queue, 'consumer_1'))
    consumer_2 = asyncio.create_task(consumer(queue, 'consumer_2'))

    producer_1 = asyncio.create_task(producer(queue, 'producer_1'))
    producer_2 = asyncio.create_task(producer(queue, 'producer_2'))

    await asyncio.sleep(10)
    consumer_1.cancel()
    consumer_2.cancel()
    
    await asyncio.gather(consumer_1, consumer_2, producer_1, producer_2, return_exceptions=True)

%time asyncio.run(main())

########## 輸出 ##########

producer_1 put a val: 5
producer_2 put a val: 3
consumer_1 get a val: 5
consumer_2 get a val: 3
producer_1 put a val: 1
producer_2 put a val: 3
consumer_2 get a val: 1
consumer_1 get a val: 3
producer_1 put a val: 6
producer_2 put a val: 10
consumer_1 get a val: 6
consumer_2 get a val: 10
producer_1 put a val: 4
producer_2 put a val: 5
consumer_2 get a val: 4
consumer_1 get a val: 5
producer_1 put a val: 2
producer_2 put a val: 8
consumer_1 get a val: 2
consumer_2 get a val: 8
Wall time: 10 s
          
        

并發編程之 Futures

區別并發和并行

  • 并發通常應用與 I/O 操作頻繁的場景,比如你要從網站上下載多個文件, I/O 操作的時間可能比 CPU 運行處理的時間長得多,通過線程和任務之間互相切換的方式實現,但同一時刻,只允許有一個線程或任務執行
  • 并行更多應用于 CPU heavy 的場景,比如 MapReduce 中的并行計算,為了加快運算速度,一般會用多臺機器,多個處理器來完成。可以讓多個進程完全同步同時的執行

Python 中之所以同一時刻只運行一個線程運行,其實是由于全局解釋鎖的存在。但對 I/O 操作而言,當其被 block 的時候,全局解釋器鎖便會被釋放,使氣體線程繼續執行。

          
            import concurrent.futures
import requests
import threading
import time

def download_one(url):
    resp = requests.get(url)
    print('Read {} from {}'.format(len(resp.content), url))

# 版本 1
def download_all(sites):
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        executor.map(download_one, sites)

# 版本 2
def download_all(sites):
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        to_do = []
        for site in sites:
            future = executor.submit(download_one, site)
            to_do.append(future)
            
        for future in concurrent.futures.as_completed(to_do):
            future.result()

def main():
    sites = [
        'https://en.wikipedia.org/wiki/Portal:Arts',
        'https://en.wikipedia.org/wiki/Portal:History',
        'https://en.wikipedia.org/wiki/Portal:Society',
        'https://en.wikipedia.org/wiki/Portal:Biography',
        'https://en.wikipedia.org/wiki/Portal:Mathematics',
        'https://en.wikipedia.org/wiki/Portal:Technology',
        'https://en.wikipedia.org/wiki/Portal:Geography',
        'https://en.wikipedia.org/wiki/Portal:Science',
        'https://en.wikipedia.org/wiki/Computer_science',
        'https://en.wikipedia.org/wiki/Python_(programming_language)',
        'https://en.wikipedia.org/wiki/Java_(programming_language)',
        'https://en.wikipedia.org/wiki/PHP',
        'https://en.wikipedia.org/wiki/Node.js',
        'https://en.wikipedia.org/wiki/The_C_Programming_Language',
        'https://en.wikipedia.org/wiki/Go_(programming_language)'
    ]
    start_time = time.perf_counter()
    download_all(sites)
    end_time = time.perf_counter()
    print('Download {} sites in {} seconds'.format(len(sites), end_time - start_time))

if __name__ == '__main__':
    main()

## 輸出
Read 151021 from https://en.wikipedia.org/wiki/Portal:Mathematics
Read 129886 from https://en.wikipedia.org/wiki/Portal:Arts
Read 107637 from https://en.wikipedia.org/wiki/Portal:Biography
Read 224118 from https://en.wikipedia.org/wiki/Portal:Society
Read 184343 from https://en.wikipedia.org/wiki/Portal:History
Read 167923 from https://en.wikipedia.org/wiki/Portal:Geography
Read 157811 from https://en.wikipedia.org/wiki/Portal:Technology
Read 91533 from https://en.wikipedia.org/wiki/Portal:Science
Read 321352 from https://en.wikipedia.org/wiki/Computer_science
Read 391905 from https://en.wikipedia.org/wiki/Python_(programming_language)
Read 180298 from https://en.wikipedia.org/wiki/Node.js
Read 56765 from https://en.wikipedia.org/wiki/The_C_Programming_Language
Read 468461 from https://en.wikipedia.org/wiki/PHP
Read 321417 from https://en.wikipedia.org/wiki/Java_(programming_language)
Read 324039 from https://en.wikipedia.org/wiki/Go_(programming_language)
Download 15 sites in 0.19936635800002023 seconds
          
        

并發編程之 Asyncio

          
            import asyncio
import aiohttp
import time

async def download_one(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            print('Read {} from {}'.format(resp.content_length, url))

async def download_all(sites):
    tasks = [asyncio.create_task(download_one(site)) for site in sites]
    await asyncio.gather(*tasks)

def main():
    sites = [
        'https://en.wikipedia.org/wiki/Portal:Arts',
        'https://en.wikipedia.org/wiki/Portal:History',
        'https://en.wikipedia.org/wiki/Portal:Society',
        'https://en.wikipedia.org/wiki/Portal:Biography',
        'https://en.wikipedia.org/wiki/Portal:Mathematics',
        'https://en.wikipedia.org/wiki/Portal:Technology',
        'https://en.wikipedia.org/wiki/Portal:Geography',
        'https://en.wikipedia.org/wiki/Portal:Science',
        'https://en.wikipedia.org/wiki/Computer_science',
        'https://en.wikipedia.org/wiki/Python_(programming_language)',
        'https://en.wikipedia.org/wiki/Java_(programming_language)',
        'https://en.wikipedia.org/wiki/PHP',
        'https://en.wikipedia.org/wiki/Node.js',
        'https://en.wikipedia.org/wiki/The_C_Programming_Language',
        'https://en.wikipedia.org/wiki/Go_(programming_language)'
    ]
    start_time = time.perf_counter()
    asyncio.run(download_all(sites))
    end_time = time.perf_counter()
    print('Download {} sites in {} seconds'.format(len(sites), end_time - start_time))
    
if __name__ == '__main__':
    main()

## 輸出
Read 63153 from https://en.wikipedia.org/wiki/Java_(programming_language)
Read 31461 from https://en.wikipedia.org/wiki/Portal:Society
Read 23965 from https://en.wikipedia.org/wiki/Portal:Biography
Read 36312 from https://en.wikipedia.org/wiki/Portal:History
Read 25203 from https://en.wikipedia.org/wiki/Portal:Arts
Read 15160 from https://en.wikipedia.org/wiki/The_C_Programming_Language
Read 28749 from https://en.wikipedia.org/wiki/Portal:Mathematics
Read 29587 from https://en.wikipedia.org/wiki/Portal:Technology
Read 79318 from https://en.wikipedia.org/wiki/PHP
Read 30298 from https://en.wikipedia.org/wiki/Portal:Geography
Read 73914 from https://en.wikipedia.org/wiki/Python_(programming_language)
Read 62218 from https://en.wikipedia.org/wiki/Go_(programming_language)
Read 22318 from https://en.wikipedia.org/wiki/Portal:Science
Read 36800 from https://en.wikipedia.org/wiki/Node.js
Read 67028 from https://en.wikipedia.org/wiki/Computer_science
Download 15 sites in 0.062144195078872144 seconds
          
        

Asyncio 是單線程的,但其內部 event loop 的機制,可以讓它并發地運行多個不同的任務,并且比多線程享有更大的自主控制權。

Asyncio 中的任務, 在運行過程中不會被打斷,因此不會出現 race condition 的情況。尤其是在 I/O 操作 heavy 的場景下, Asyncio 比多線程的運行效率更高,因此 Asyncio 內部任務切換的損耗,遠比線程切換的損耗要小,并且 Asyncio 可以開啟的任務數量,也比多線程中的線程數列多得多。

但需要注意的是,很多情況下,使用 Asyncio 需要特定第三方庫的支持,而如果 I/O 操作很快,并不 heavy ,建議使用多線程來解決問題。

GIL(全局解釋器鎖)

CPython 引進 GIL 主要是由于:

  • 設計者為了規避類似于內存管理這樣的復雜的競爭風險問題
  • 因為 CPython 大量使用 C 語言庫,但大部分 C 語言庫都不是原生線程安全的(線程安全會降低性能和增加復雜度)

GIL 的設計,主要是為了方便 CPython 解釋器層面的編寫者,而不是 Python 應用層面的程序員。

可以使用 import dis 的方式將代碼編譯成 bytecode

垃圾回收機制

  • 垃圾回收是 Python 自帶的機制,用于自動釋放不會再用到的內存空間
  • 引用計數是其最簡單的實現,不過切記,這只是充分非必要條件,因為循環引用需要通過不可達判定,來確定是否可以回收
  • Python 的自動回收算法包括標記清除和分代收集,主要針對的是循環引用的垃圾收集
  • 調試內存泄漏方便,objgraph 是很好的可視化分析工具

編程規范

閱讀者的體驗 > 編程者的體驗 > 機器的體驗

  • 學會合理分解代碼,提高代碼可讀性
  • 合理利用 assert(線上環境禁止使用)
  • 啟用上下文管理器和 with 語句精簡代碼
  • 單元測試
  • pdf & cprofile

更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久午夜综合久久 | 国产午夜精品尤物福利视频 | 久久亚洲精品久久久久 | 亚洲图片天堂 | 成人免费黄色 | 美女久久久久 | 日本特级 | 精品亚洲一区二区三区 | 日本一片免费观看高清完整 | 色综合在 | 99久久综合 | 久久精品国产主播一区二区 | 国产成人精品在线观看 | 色网站在线观看 | 天天干天天曰 | 亚洲高清成人欧美动作片 | 免费xxx | 国产欧美一区二区精品性色99 | 国产国产成人人免费影院 | 精品久久中文久久久 | 四虎永久免费在线观看 | 国产一区二区福利久久 | 国产一区二区三区免费在线视频 | 奇米7777影视 | 婷婷免费视频 | 国产乱人伦av在线a 国产乱人伦精品一区二区 国产乱人伦偷精品视频不卡 | 国产麻豆精品高清在线播放 | 国产精品aaa | 亚洲欧美日韩不卡一区二区三区 | 久久99影院 | 美女黄频视频大全免费高清 | 青青青国产免费线在 | 国产精品久久久亚洲动漫 | 国产一级特黄生活片 | 免费毛片看 | 91精品国产闺蜜国产在线 | 四虎国产精品免费视 | 日本黄色录像视频 | 久久亚洲欧美 | 羞羞的视频网站 | 手机看片福利盒子久久青 |