Python多线程

96
人生苦短啊
2018.09.04 16:34* 字数 219

1. 多线程的实现方式

第一种是调用方法

import threading
import time


def get_detail_html(url):
    print("get detail html ")
    time.sleep(2)
    print("get detail html end")


def get_detail_url(url):
    print("get detail url ")
    time.sleep(2)
    print("get detail url end")

if __name__=="__main__":
    thread1 = threading.Thread(target=get_detail_html, args=("",))
    thread2 = threading.Thread(target=get_detail_url, args=("",))

    start_time = time.time()
    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()
    # 主线程提出时候, 子线程kill掉

    print("last time: {}".format(time.time() - start_time))

第二种是使用类继承threading.Thread

class GetDetailHtml(threading.Thread):
    def __init__(self, name):
        super().__init__(name=name)

    def run(self):
        print("get detail html started")
        time.sleep(2)
        print("get detail html end")


class GetDetailUrl(threading.Thread):
    def __init__(self, name):
        super().__init__(name=name)

    def run(self):
        print("get detail url started")
        time.sleep(4)
        print("get detail url end")

if __name__=="__main__":
    thread1 = GetDetailHtml("get_detail_html")
    thread2 = GetDetailUrl("get_detail_url")

    start_time = time.time()
    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()
    # 主线程提出时候, 子线程kill掉

    print("last time: {}".format(time.time() - start_time))

2. Python的全局解释器锁(GIL)

一直以来都感觉用python开发的时候运行速度挺慢的,其实有时候是它在影响, 下面代码开启两个线程,一个加1000000次一个减1000000次,结果每次执行结果都是不一样的

#gil global interpreter lock (cpython)
#python中一个线程对应于c语言中的一个线程
#gil使得同一个时刻只有一个线程在一个cpu上执行字节码, 无法将多个线程映射到多个cpu上执行

#gil会根据执行的字节码行数以及时间片释放gil,gil在遇到io的操作时候主动释放

total = 0

def add():
    global total
    for i in range(1000000):
        total += 1
def desc():
    global total
    for i in range(1000000):
        total -= 1

import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()

thread1.join()
thread2.join()
print(total)          # 318676

3. 线程同步

使用锁使线程同步

from threading import Lock, RLock, Condition #可重入的锁

total = 0
lock = Lock()
def add():
    global lock
    global total
    for i in range(1000000):
        lock.acquire()
        total += 1
        lock.release()


def desc():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total -= 1
        lock.release()

import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()

thread1.join()
thread2.join()
print(total)        # 0

4. 重用锁

如果想要在一个方法里加上多个锁, Lock是做不到的就需要用RLock才可以重复用锁

from threading import Lock, RLock#可重入的锁

#在同一个线程里面,可以连续调用多次acquire, 一定要注意acquire的次数要和release的次数相等
total = 0
lock = RLock()
def add():
    #1. dosomething1
    #2. io操作
    # 1. dosomething3
    global lock
    global total
    for i in range(1000000):
        lock.acquire()
        lock.acquire()
        total += 1
        lock.release()
        lock.release()


def desc():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total -= 1
        lock.release()

import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()


#
thread1.join()
thread2.join()
print(total)  # 0

"""

5. 死锁的原因

伪代码解释一下死锁, A 调用 a 的, 同时 B 在掉用 b, A为了要执行下去 A 会调用 b, 但是B并没有释放 b, B又在等待A释放 a 这样就会造成死锁

#1. 用锁会影响性能
#2. 锁会引起死锁

"""
A(a、b)
acquire (a)
acquire (b)

B(a、b)
acquire (b)
acquire (a)
Python