7.python之线程

什么是线程

线程是应用程序中工作的最小单元,或者称之为微进程.它是进程的实际运作单位,一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

threading.currentThread(): 返回当前的线程变量。
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

run(): 用以表示线程活动的方法。
start():启动线程活动。 
join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
setDaemon(True):守护主线程,跟随主线程退(必须要放在start()上方)
isAlive(): 返回线程是否活动的。
getName(): 返回线程名。
setName(): 设置线程名。

开启线程的两种方式

from threading import Thread

def f1(n):
    print("%s号线程"%n)

def f2(n):
    print("%s号线程"%n)

if __name__ == '__main__':
    p1 = Thread(target=f1,args=(1,))
    p2 = Thread(target=f1, args=(2,))
    p1.start()
    p2.start()

    print("主线程")
第一种方式
from threading import Thread
class Mythread(Thread):
    def __init__(self,name):
        super(Mythread, self).__init__()
        self.name = name

    def run(self):
        print("%s号线程"%self.name)


if __name__ == '__main__':
    p1 = Mythread("alex")
    p1.start()


    print("主线程")
第二种方式

查看线程的进程

import os
from threading import Thread

def f1(n):
    print("1号",os.getpid())
    print('%s号线程任务'%n)

def f2(n):
    print('2号',os.getpid())
    print('%s号线程任务'%n)

if __name__ == '__main__':
    t1 = Thread(target=f1,args=(1,))
    t2 = Thread(target=f2,args=(2,))
    t1.start()
    t2.start()
    print('主线程',os.getpid())
    print('主线程')
pid

验证线程数据共享

import time
from threading import Thread

num =100
def f1():
    time.sleep(3)
    global num
    num = 3
    print('子线程num',num)

if __name__ == '__main__':
    t = Thread(target=f1)
    t.start()
    t.join()
    print("主线程中的num",num)
View Code

线程与进程的效率对比

# -*- coding:utf-8 -*-
import time
from threading import Thread
from multiprocessing import Process

def f1():
    n = 10
    for i in range(100):
        n+=i

if __name__ == '__main__':
    t_s_time = time.time()
    t_list = []
    for i in range(20):
        t = Thread(target= f1,)
        t.start()
        t_list.append(t)
    [tt.join() for tt in t_list]
    t_e_time = time.time()
    t_dir_time = t_e_time - t_s_time

    p_s_time = time.time()
    p_list = []
    for i in range(20):
        p = Process(target=f1,)
        p.start()
        p_list.append(p)

    [pp.join() for pp in p_list]
    p_e_time = time.time()
    p_dir_time = p_e_time - p_s_time
    print("多线程执行时间:",t_dir_time)
    print("多进程执行时间:",p_dir_time)
View Code

守护线程

守护线程会等待主程序运行完毕后被销毁

运行完毕并非运行终止

import time
from threading import Thread
from multiprocessing import Process

# 守护进程:主进程代码执行运行结束,守护进程随之结束
#守护线程:守护线程会等待所有非守护线程运行结束才结束

def f1():
    time.sleep(2)
    print('1号进程')

def f2():
    time.sleep(3)
    print('2号进程')

if __name__ == '__main__':
    t1 = Thread(target=f1,)
    t2 = Thread(target=f2,)
    t1.daemon = True
    t2.daemon = True
    t1.start()
    t2.start()
    print('主线程')


# if __name__ == '__main__':
#     p1 = Process(target=f1,)
#     p2 = Process(target=f2,)
    # p1.daemon = True
    # p2.daemon = True
    # p1.start()
    # p2.start()
    # print("主进程")
View Code

GIL锁

GIL本质是一把互斥锁

 

# -*- coding:utf-8 -*-
import time
from threading import Lock ,Thread

num =100
def f1(loc):
    loc.acquire()
    global num
    tmp = num
    tmp -= 1
    time.sleep(0.001)
    num = tmp
    loc.release()

if __name__ == '__main__':
    t_loc = Lock()
    t_list = []
    for i in range(10):
        t = Thread(target=f1,args=(t_loc,))
        t.start()
        t_list.append(t)
    [tt.join() for tt in t_list]

    print("主线程num",num)
Lock锁
from threading import Thread,Lock,RLock
import time

def f1(locA,locB):

    locA.acquire()
    print("f1>>>1号抢到了A锁")
    time.sleep(1)
    locB.acquire()
    print("f1>>>1号抢到了B锁")
    locB.release()
    locA.release()


def f2(locA,locB):
    locB.acquire()
    print("f2>>>2号抢到了B锁")
    locA.acquire()
    time.sleep(1)
    print("f2>>>2号抢到了A锁")
    locA.release()
    locB.release()

if __name__ == '__main__':
    locA = Lock()
    locB = Lock()
    t1 = Thread(target=f1,args=(locA,locB))
    t2 = Thread(target=f2,args=(locA,locB))
    t1.start()
    t2.start()
锁死现象
# -*- coding:utf-8 -*-
from threading import Thread,Lock,RLock
import time

def f1(locA,locB):

    locA.acquire()
    print("f1>>>1号抢到了A锁")
    time.sleep(1)
    locB.acquire()
    print("f1>>>1号抢到了B锁")
    locB.release()
    locA.release()


def f2(locA,locB):
    locB.acquire()
    print("f2>>>2号抢到了B锁")
    locA.acquire()
    time.sleep(1)
    print("f2>>>2号抢到了A锁")
    locA.release()
    locB.release()

if __name__ == '__main__':

    locA = locB = RLock()
    t1 = Thread(target=f1,args=(locA,locB))
    t2 = Thread(target=f2,args=(locA,locB))
    t1.start()
    t2.start()
递归锁

信号量Semaphore

import time,os
from threading import Thread,Semaphore

def func():
    sm.acquire()
    print("get sm")
    time.sleep(1)
    sm.release()
if __name__ == '__main__':
    sm = Semaphore(os.cpu_count())
    for i in range(23):
        t = Thread(target=func)
        t.start()
View Code

Event

from threading import Event
e = Event() #初始状态False
print(e.is_set())

print('开始等待')
e.set() #将事件对象的状态改为True
# e.clear() #将事件对象的状态改为false
e.wait() #当e对象的状态为False的时候会在这个地方阻塞,改为true之后就直接往下执行
print('结束')
View Code

 线程的其他方法

Threading.current_thread() #当前线程对象
current_thread().getName() #获取线程名
current_thread().ident  #获取线程id
Threading.Enumerate() #当前正在运行的线程对象的一个列表
Threading.active_count() #当前正在运行的线程数量
# -*- coding:utf-8 -*-
import threading
import time
from threading import Thread,current_thread

def f1(n):
    time.sleep(1)
    print("子线程名称",current_thread().getName())#子线程名称 Thread-1
    print("%s号线程任务"%n)#1号线程任务

if __name__ == '__main__':
    t1 = Thread(target=f1,args=(1,))
    t1.start()
    print("主线程名称",current_thread().getName())#主线程名称 MainThread
    print("主线程Id",current_thread().ident)#主线程Id 12184
    print(current_thread())#<_MainThread(MainThread, started 12184)>
    print(threading.enumerate())#[<_MainThread(MainThread, started 12184)>, <Thread(Thread-1, started 12172)>]
    print(threading.active_count())#2
View Code

线程队列

先进先出队列:queue.Queue(5)
先进后出\后进先出队列:queue.LifoQueue(5) 
优先级队列:queue.priorityQueue(5)
put的数据是一个元组,元组的第一个参数是优先级数字,数字越小优先级越高,越先被get到被取出来,
第二个参数是put进去的值,如果说优先级相同,那么值别忘了应该是相同的数据类型,字典不行
# -*- coding:utf-8 -*-
import queue
# 一:先进先出队列
q = queue.Queue(3)
q.put(1)
q.put(2)
q.put(3)
print("当前队列的内容长度",q.qsize())
print('查看队列是否满了',q.full())
try:
    q.put_nowait(4)
except Exception:
    print("队列满了")
print(q.get())
print(q.get())
print(q.get())
print("查看队列是否为空",q.empty())
try:
    q.get_nowait()
except Exception:
    print("队列为空")

#队列先进后出
# q = queue.LifoQueue(3)
# q.put(1)
# q.put(2)
# q.put(3)
#
# print(q.get())
# print(q.get())
# print(q.get())

#优先级队列
# q = queue.PriorityQueue(5)
# q.put((4,"alex"))
# q.put((2,'zalex'))#如果优先级数字相同,如果数据类型不同会报错
# q.put((2,{'k':666}))
# q.put((5,(2,3)))
# q.put((1,(1,2)))
# q.put((-10,(1,2)))
#
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())
#
# q.put((2,(2,3))) #优先级相同会比较第二个参数在ascii的位置,如果数据类型不同会报错
# q.put((2,(1,3)))
# print(q.get())
# print(q.get())
View Code

线程池

p.map(f1,可迭代的对象)  #异步执行
res.result()  #和get方法一样,如果没有结果,会等待,阻塞程序
shutdown() #close+join,锁定线程池,等待线程池中所有已经提交的任务全部执行完毕
# -*- coding:utf-8 -*-
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from threading import current_thread
import time

def f1(n,s):
    time.sleep(1)
    # print("%s号子线程"%current_thread().ident)
    # print(n,s)
    return n+s

if __name__ == '__main__':
    tp = ThreadPoolExecutor(4)
    # tp = ProcessPoolExecutor(4)
    # s = tp.map(f1,range(5))  #异步提交任务,参数同样是任务名称,可迭代对象
    res_list = []
    for i in range(10):
        res = tp.submit(f1,i,1) #submit是给线程池异步提交任务,
        print(res)
        res_list.append(res)

    tp.shutdown()#主线程等待所有提交给线程池的任务,全部执行完毕 close + join
    for r in res_list:
        print(r.result())
    print('主线程结束')
View Code

线程回调函数

import time
from threading import current_thread
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

def f1(n,s):
    return n+s
def f2(n):
    print('回调函数>>>',n.result())

if __name__ == '__main__':
    tp = ThreadPoolExecutor(4)
    res = tp.submit(f1,11,12).add_done_callback(f2)
View Code

 

posted @ 2019-02-24 15:11  等待の喵  阅读(830)  评论(0编辑  收藏  举报