在计算机中,一个程序就是一个进程,一个进程里面可以有一个或多个线程,线程是真正使程序运行的东西。
关于进程和线程的关系,简单理解:进程与线程的一个简单解释
一、添加线程
1. threading模块
import threading
def main():
print(threading.active_count()) # active threading numbers is 2
print(threading.enumerate()) #[<_MainThread(MainThread, started 4321387392)>, <Thread(SockThread, started daemon 123145543471104)>]
print(threading.current_thread()) #<_MainThread(MainThread, started 4321387392)>
if __name__ == '__main__':
main()
2.添加线程
import threading
def thread_job():
print("This is an added Thread, number is %s"%threading.current_thread())
def main():
target=thread_job()
added_thread = threading.Thread(target) #定义线程,接收参数target代表这个线程要完成的任务
added_thread.start()
if __name__ == '__main__':
main()
3.线程是各自工作互不干扰的,如下:
import threading
import time
def T1_job():
print("T1 start\n")
time.sleep(1) # 任务间隔1s
print("T1 finish\n")
added_thread = threading.Thread(target=T1_job, name='T1') #注意此处target只是一个索引,所以不用函数的()
added_thread.start()
print("all done\n")
输出结果为
T1 start
all done
>>> T1 finish
你是不是认为这个程序应该输出的是
T1 start
T1 finish
all done
才对?
问题出现是因为主线程先于子线程结束。
怎么让子线程在主线程前门结束,主线程最后结束呢?
我们可以用join()
启动线程后,对它调用join()函数:
added_thread.start()
added_thread.join()
print("all done\n")
这一次all done会最后才输出。
所以用join来控制多线程的执行顺序是非常有用的。
4. Queue功能
将多线程的结果存储进Queue,看如下例子:
import threading
import time
import queue
def job(l,q): #对列表的每个元素进行平方计算,将结果保存在队列中
for i in range(len(l)):
l[i] = l[i]**2 #平方
q.put(l) #多线程调用的函数不能用return返回值
def multithreading():
q = queue.Queue() #q中存放返回值,代替return的返回值
threads = [] #定义一个多线程列表
data = [[1,1],[2,3,4,5],[6],[7,8,9]] #初始化一个多维数据列表,用来处理
for i in range(4): #定义四个线程
t = threading.Thread(target=job,args=(data[i],q)) #Thread首字母要大写,被调用的job函数没有括号,只是一个索引,参数在后面
t.start() #开始线程
threads.append(t) #把每个线程append到线程列表中
for thread in threads: #分别join四个线程到主线程
thread.join()
results = [] #定义一个空的列表results
for j in range(4): #将四个线程运行后保存在队列中的结果返回给空列表results
results.append(q.get()) #q.get()按顺序从q中拿出一个值
print(results)
if __name__=='__main__':
multithreading()
输出结果为:[[1, 1], [4, 9, 16, 25], [36], [49, 64, 81]]
5. 线程锁
对于两个线程同时操作一个共享的数据,如果不用锁,会造成数据混乱
如:(不用线程锁)
import threading
def job1():
global A
for i in range(10):
A += 1
print("job1:A=",A)
def job2():
global A
for i in range(10):
A += 10
print("job2:A=",A)
if __name__=='__main__':
A = 0
t1 = threading.Thread(target=job1)
t2 = threading.Thread(target=job2)
t1.start()
t2.start()
t1.join()
t2.join()
输出结果为:
job1:A=job2:A= 111
job1:A=job2:A= 1222
job1:A=job2:A= 2333
job1:A=job2:A= 3444
job1:A=job2:A= 4555
job1:A=job2:A= 5666
job1:A=job2:A= 6777
job1:A=job2:A= 7888
job1:A=job2:A= 8999
job1:A=job2:A= 100110
使用线程锁:
在要操作数据前上锁,操作完数据后释放锁,这样就不会有同时修改数据的情况出现:
import threading
def job1():
global A,lock
lock.acquire()
for i in range(10):
A += 1
print("job1:A=",A)
lock.release()
def job2():
global A,lock
lock.acquire()
for i in range(10):
A += 10
print("job2:A=",A)
lock.release()
if __name__=='__main__':
A = 0
lock = threading.Lock()
t1 = threading.Thread(target=job1)
t2 = threading.Thread(target=job2)
t1.start()
t2.start()
t1.join()
t2.join()
输出结果为:
job1:A= 1
job1:A= 2
job1:A= 3
job1:A= 4
job1:A= 5
job1:A= 6
job1:A= 7
job1:A= 8
job1:A= 9
job1:A= 10
job2:A= 20
job2:A= 30
job2:A= 40
job2:A= 50
job2:A= 60
job2:A= 70
job2:A= 80
job2:A= 90
job2:A= 100
job2:A= 110
参考自:Threading 学会多线程