一、线程的基本概念:
线程被称为轻量级进程。
计算机的执行单位以线程为单位。计算机的最小可执行是线程。
进程是资源分配的基本单位。线程是可执行的基本单位,是可被调度的基本单位。
线程不可以自己独立拥有资源。线程的执行必须依赖所属进程中的资源。
进程中必须至少有一个线程。
由于GIL(全局解释锁,只在Cpython中有),导致线程没有真正的并行。
线程分为用户级线程和内核级线程。
二、进程由 代码段、数据段、PCB(进程控制块)组成
线程由 代码块、数据块、TCB(线程控制块)组成
三、线程和进程的比较
thread -- 线程
导入线程模块的两种方法:
import threading
from threading import Thread
(1) cpu 切换进程比切换线程 慢很多。在python中,如果IO操作过多的话,使用多线程最好了。
(2) 在同一进程内,所有线程共享这个进程的pid,也就是说所有的线程共享所属进程的资源和内存。
(3) 在同一个进程内,所有线程共享该进程中的全局变量
(4) 因为有GIL锁的存在,在Cpython中,没有真正的线程并行。但是有多进程并行
当任务是计算密集的情况下使用多进程。
(5) 守护线程和守护进程的区别
守护进程:要么自己正常结束,要么等主进程的代码结束。
守护线程:要么自己正常结束,要么要等主进程的进程结束。
四、线程的使用方法。
(1)锁机制
递归锁 Rlock() 可以有无数的锁,但是这些锁有一把万能钥匙。

from threading import Thread, RLock
def fn(r_tot, r_pap):
r_tot.acquire()
print('我在厕所')
r_pap.acquire()
print('我还有纸')
r_tot.release()
r_pap.release()
def fn1(r_pap, r_tot):
r_pap.acquire()
print('wo也有纸')
r_tot.acquire()
print('我想上厕所')
r_pap.release()
r_tot.release()
r_tot = r_pap = RLock()
t1 = Thread(target=fn, args=(r_tot, r_pap))
t2 = Thread(target=fn1, args=(r_pap, r_tot))
t1.start()
t2.start()

互斥锁 Lock() 一把锁配一把钥匙
GIL:全局解释锁 锁的是线程,同一时间只允许一个线程访问cpu
(2)信号量
from threading import Semaphore

from threading import Thread, Semaphore
import time
def fn(s, i, color):
s.acquire()
print('%s%s个小浣熊出生了\033[0m' % (color, i))
time.sleep(1)
s.release()
def fn1(s, i, color):
s.acquire()
print('%s%s个大灰狼来吃小浣熊了\033[0m' % (color, i))
s.release()
s = Semaphore(5)
for i in range(10):
t1 = Thread(target=fn, args=(s, (i + 1), '\033[35m'))
t2 = Thread(target=fn1, args=(s, (i + 1), '\033[36m'))
t1.start()
t2.start()

(3)事件
from threading import Event

from threading import Thread,Event
import time,random
def conn_mysql(e,i):
count = 1
while count <= 3:
if e.is_set():
print('第%s个人连接成功!'%i)
break
print('正在尝试第%s次重新连接...'%(count))
e.wait(0.5)
count += 1
def check_mysql(e):
print('\033[42m 数据库正在维护 \033[0m')
time.sleep(random.randint(1,2))
e.set()
if __name__ == '__main__':
e = Event()
t_check = Thread(target=check_mysql,args=(e,))
t_check.start()
for i in range(10):
t_conn = Thread(target=conn_mysql,args=(e,i))
t_conn.start()
(4)条件
from threading import Condition
条件是让程序员自行去调度线程的一个机制
Condition 有四个方法
acquire()
release()
wait() 是让线程阻塞
notify(int) 是指给wait发一个信号,让wait 变成 不阻塞
int 是指,要给多少个wait 发信号

from threading import Thread,Condition
def func(con,i):
con.acquire()
con.wait()# 线程执行到这里,会阻塞住,等待notify发送信号,来唤醒此线程
con.release()
print('第%s个线程开始执行了!'%i)
if __name__ == '__main__':
con = Condition()
for i in range(10):
t = Thread(target=func,args=(con,i))
t.start()
while 1:
num = int(input(">>>"))
con.acquire()
con.notify(num)# 发送一个信号给num个正在阻塞在wait的线程,让这些线程正常执行
con.release()
(5)定时器
from threading import Timer
Timer(time, func)
time:表示睡眠的时间,以秒为单位
func:睡眠之后需要执行的任务。

from threading import Timer
def fn():
print('我要执行了')
print(type(te))
te = Timer(2, fn) # 等待2秒,然后执行fn。
te.start()
五、线程池
from concurrent.futures import ThreadPoolExector
concurrent.futures 这个模块是异步调用的机制
提交任务的方法有两种:
t = ThreadPoolExector
1. t.submit(func,参数)
2. t.map(func,可迭代对象)
在进程池中用 apply_async() 时,主进程要写close 和 join
在线程池中 要写shutdown 作用相当于进程池中的 close + join
不同的提交任务的方式获取值的方法也不同。
t.submit()提交,需要用result()来获取

t.map() 提交,需要用__next__来获取


from concurrent.futures import ThreadPoolExecutor
def fn(num):
sum = 0
for i in range(num):
sum += i
print(sum)
t = ThreadPoolExecutor()
for i in range(10)
t.submit(fn,i)
t.shutdown()

from concurrent.futures import ThreadPoolExecutor
def fn(i):
num = 0
for el in range(i):
num += el
print(num)
t = ThreadPoolExecutor(5)
t.map(fn, range(10))
t.shutdown()
线程池中的回调函数
线程中的回调函数是由子线程调用的


from concurrent.futures import ThreadPoolExecutor
import time
import threading
def fn1(num):
time.sleep(2)
print('子线程', threading.current_thread())
return num
def fn2(sta):
time.sleep(2)
print('回调函数', threading.current_thread())
t = ThreadPoolExecutor()
print('主线程', threading.current_thread())
time.sleep(2)
for i in range(2):
t.submit(fn1, i).add_done_callback(fn2)
t.shutdown()

from concurrent.futures import ThreadPoolExecutor
def fn1(num):
sum = 0
for i in range(num):
sum += i
return sum
def fn2(sta):
print(sta.result())
t = ThreadPoolExecutor()
for i in range(10):
t.submit(fn1, i).add_done_callback(fn2)
t.shutdown()
来源:https://www.cnblogs.com/wf123/p/9525730.html
