Day036--Python--线程

1. 线程

  

from threading import Thread

def func(n):
    print(n)

if __name__ == '__main__':
    t = Thread(target=func, args=(3,))
    t.start()
    print('主线程结束')
View Code创建进程方法一
from threading import Thread

class MyThread(Thread):
    def run(self):
        print('XXX')

if __name__ == '__main__':
    t = MyThread()
    t.start()
    print('主线程结束')
View Code创建进程方法二

 

 

2. 线程和进程的效率对比

  线程的效率非常高, 而且线程的开启不需要消耗资源

import time
from threading import Thread
from multiprocessing import Process

def func(n):
    num = 0
    for n1 in range(n):    # 做个运算, 消耗一下时间, 好比较线程与进程的效率
        num += n1
    print('num', num)

if __name__ == '__main__':
    t_s_t = time.time()   # 线程运行起始时间
    tlst = []
    for i in range(10):
        t = Thread(target=func, args=(10,))
        t.start()
        tlst.append(t)
    [t.join() for t in tlst]   # 迭代着join等待线程全部运行完毕
    t_e_t = time.time()      # 线程运行结束时间
    t_dif_t = t_e_t - t_s_t   # 计算线程的运行时间差
    
    print('线程的结束时间', t_dif_t)
    p_s_t = time.time()
    plst = []
    for i in range(10):
        p = Process(target=func, args=(10,))
        p.start()
        plst.append(p)
    [p.join() for p in plst]

    p_e_t = time.time()
    p_dif_time = p_e_t - p_s_t
    print('进程的结束时间', p_dif_time)
    print('主线程结束', t_dif_t)

 

 

3. 线程之间数据共享

from threading import Thread

num = 100
def func():
    global num
    num = 0

if __name__ == '__main__':
    t = Thread(target=func)
    t.start()
    print(num)
    t.join()
    print('主线程结束')
View Code 线程间数据共享

 

import time
import random
from threading import Thread

n = 100
def func():
    global n
    x = n
    x = x - 1
    time.sleep(random.random())
    n = x

if __name__ == '__main__':

    for i in range(30):
        t_lst = []
        for i in range(10):
            t = Thread(target=func)
            t.start()
            t_lst.append(t)
        # [t.join() for t in t_lst]
        print(n)
View Code 数据共享, 不安全

 

 

import time
from threading import Thread, Lock

num = 100
def func(t_lock):
    global num
    t_lock.acquire()
    mid = num
    mid = mid - 1
    time.sleep(0.0000001)
    num = mid
    t_lock.release()

if __name__ == '__main__':
    t_lock = Lock()
    t_lst = []
    for i in range(10):
        t = Thread(target=func, args=(t_lock,))
        t.start()
        t_lst.append(t)
    [t.join() for t in t_lst]

    print('主线程>>>', num)
View Code 共享数据加锁保障安全

 

 

 

 

 

4. 锁(同步锁/互斥锁) 

  1. GIL (Global Interpreter Lock) 全局解释锁

  2. Lock  同步锁/互斥锁

  3. RLock  递归锁

  保证数据安全, 但是牺牲了效率, 同步执行锁内代码

  死锁现象: 当我们使用锁嵌套锁时, 多个线程异步执行的时候会出现线程之间相互争夺对方未释放的锁, 相互等待.   (互相抢到了对方需要的锁, 导致双方相互等待, 程序没法进行)

import time
from threading import Thread, Lock

class MyThread(Thread):

    def __init__(self, lockA, lockB):
        super().__init__()
        self.lockA = lockA
        self.lockB = lockB

    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        self.lockA.acquire()
        print('我拿了A锁')
        self.lockB.acquire()
        print('我拿了B锁')
        print('我是f1')
        self.lockB.release()
        self.lockA.release()

    def f2(self):
        self.lockB.acquire()
        time.sleep(1)
        print('拿到了B锁')
        self.lockA.acquire()
        print('拿到了A锁')
        print('我是f2')
        self.lockA.release()
        self.lockB.release()

if __name__ == '__main__':
    lockA = Lock()
    lockB = Lock()
    t1 = MyThread(lockA, lockB)
    t1.start()

    t2 = MyThread(lockA, lockB)
    t2.start()

    print('我是主线程')
View Code 死锁现象

   

 

  解决死锁: 递归锁 RLock   可以多次acquire, 通过一个计数器来记录被锁了多少次, 只有计数器为0的时候, 大家才能继续抢锁.

 

import time
from threading import Thread, Lock, RLock


class MyThread(Thread):

    def __init__(self, lockA, lockB):
        super().__init__()
        self.lockA = lockA
        self.lockB = lockB

    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        self.lockA.acquire()
        print('我拿了A锁')
        self.lockB.acquire()
        print('我拿了B锁')
        print('我是f1')
        self.lockB.release()
        self.lockA.release()

    def f2(self):
        self.lockB.acquire()
        time.sleep(1)
        print('拿到了B锁')
        self.lockA.acquire()
        print('拿到了A锁')
        print('我是f2')
        self.lockA.release()
        self.lockB.release()


if __name__ == '__main__':
    lockA = lockB = RLock()
    t1 = MyThread(lockA, lockB)
    t1.start()

    t2 = MyThread(lockA, lockB)
    t2.start()

    print('我是主线程')
View Code 递归锁, 解决死锁

 经典问题: 科学家吃面

import time
from threading import Thread,Lock, RLock

def eat1(name, lockA, lockB):
    lockA.acquire()
    print('%s抢到了叉子' % name)
    lockB.acquire()
    print('%s抢到了面条' % name)
    print('%s开始吃面啦~~' % name)
    lockB.release()
    lockA.release()


def eat2(name, lockA, lockB):
    lockB.acquire()
    print('%s抢到了面条' % name)
    time.sleep(1)
    lockA.acquire()
    print('%s抢到了叉子' % name)
    print('%s开始吃面啦~~~' % name)
    lockA.release()
    lockB.release()

if __name__ == '__main__':
    lockA = lockB = RLock()
    # lockA = Lock()
    # lockB = Lock()
    for name in ['alex', 'wu sir', 'boss king', 'taibai']:
        t1 = Thread(target=eat1, args=(name, lockA, lockB))
        t1.start()
        t2 = Thread(target=eat2, args=(name, lockA, lockB))
        t2.start()
View Code死锁和递归锁解决死锁

 

       

 

5. 守护线程 

  主进程代码结束程序并没有结束,并且主进程还存在,进程等待其他的子进程执行结束以后,为子进程收尸,注意一个问题:主进程的代码运行结束守护进程跟着结束,

守护线程:

  主线程等待所有非守护线程的结束才结束,主线程的代码运行结束,还要等待非守护线程的执行完毕.这个过程中守护线程还存在

import time
from multiprocessing import Process
from threading import Thread

def func(n):
    time.sleep(5)
    print(n)

if __name__ == '__main__':
    # 主线程等待的是子线程的任务全部执行完毕
    t = Thread(target=func, args=('我是子线程',))
    t.start()
    # 主进程等待的是给子进程收尸, 回收资源,各种信息
    # p = Process(target=func, args=('我是子进程',))
    # p.start()
    print('主线程结束')
View Code 主线程等待子线程的原因
import time
from multiprocessing import Process
from threading import Thread

def func1(n):
    time.sleep(5)
    print(n)

def func2(n):
    time.sleep(2)
    print(n)

if __name__ == '__main__':
    # p1 = Process(target=func1, args=('我是1号',))
    # p1.daemon = True
    # p1.start()
    # p2 = Process(target=func2, args=('我是2号',))
    # p2.start()
    t1 = Thread(target=func1, args=('我是1号',))
    # t1.daemon = True
    t1.start()
    t2 = Thread(target=func2, args=('我是2号',))
    t2.daemon = True  # 等待所有非守护线程结束
    t2.start()

    print('主线程结束')  # 守护进程在主进程运行代码结束时跟着结束, 不会跟着其他子进程执行
View Code 守护线程与守护进程差别

 

  

6. 信号量

  控制同时能够进入锁内去执行代码的线程数量(进程数量), 维护了一个计数器, 刚开始创建信号量的时候, 假如设置的是4个房间, 进入一次acquire就减1, 出来一个就+1, 如果计数器为0, name其他的任务等待, 这样其他的任务和正在执行的任务是一个同步的状态, 而进入acquire里面去执行的那4个任务是异步执行的.

# 和进程中信号量的按摩房一个道理, 相当于有多把锁
import time
from threading import Thread, Semaphore

def func1(s):
    s.acquire()
    time.sleep(1)
    print('你好啊')
    s.release()

if __name__ == '__main__':
    s = Semaphore(4)
    for i in range(10):
        t = Thread(target=func1, args=(s,))
        t.start()

 

 

超哥博客--Python之线程

posted @ 2018-10-26 15:30  SuraSun  阅读(226)  评论(0编辑  收藏  举报