前言:本系列将包含Python并行编程的相关技术内容,包括Python线程、Python进程、并发编程的异步模式及终极大法Python分布式计算如Celery、SCOOP等相关技术。
关键词: threading multiprocessing asyncio Celery
线程的基本概念和线程的两种定义方法
线程是什么?
线程看起来就像轻量级的进程,而进程又是什么呢? 进程即我们平时运行程序,比如通过点击图标打开的浏览器,QQ都是进程,进程拥有自己的独立的内存空间地址,可以拥有多个线程;即线程是存在进程内,也就意味着一个进程内的线程可以共享一些资源,其线程间的切换也就比进程低得多,多个线程可以并行及并发执行,共享数据和资源,所以我们多数时候的线程通信都是利用共享信息的空间进行通信,这也是后面谈到的线程管理必备的多种线程通信方式了。
在Python怎么定义线程?
使用线程最简单的方式就是通过目标函数的实例化:
import threading
import time
# 用于实例化线程目标函数
def function(i):
time.sleep(2)
print('Thread {} is running.'.format(i))
time.sleep(2)
return
for i in range(5):
# Python模块threading.Thread方法
t = threading.Thread(target=function, args=(i, ))
t.start()
复制代码
运行截图如下:
通过以上程序我们看出,定义好我们需要运行的目标函数来实例化线程,然后传入参数
target
即函数名,然后如果需要运行的目标函数有参数需要传递的话即可传入
args
元组,注意此处传入的是
元组tuple
。 然后我们在调用
start()
方法后启动实例化的线程
使用线程模块实现新的线程:
import threading
import time
class myThread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
def run(self):
time.sleep(2)
print('Thread {} is running.'.format(self.i))
time.sleep(2)
return
for i in range(1, 6):
t = myThread(i)
t.start()
复制代码
运行截图如下:
通过上面的程序我们可以看出,我们需要定义新的Thread类的子类,并且通过重写
__init__
方法来传递参数,然后重写
run()
方法来实现目标函数,那么当我们创建出新的子类后就可以实例化该子类并通过
start()
方法来启动线程。
守护线程 setDaemon(True)
接下来我们在运行一段代码:
import threading
import time
class myThread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
def run(self):
time.sleep(2)
print('Thread {} is running.'.format(self.i))
time.sleep(2)
return
print('Mian THread starting')
for i in range(1, 6):
t = myThread(i)
t.start()
print('Mian THread end')
复制代码
运行截图如下:
当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,主线程会创建多个子线程;我们在主线程添加了两句
print()
用于打印主线程的运行状态,我们可以看见在默认情况下主现成直接执行完就退出了,此时子线程们还在执行过程中,那么如果我们添加setDaemon(True)方法呢:
import threading
import time
class myThread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
def run(self):
time.sleep(2)
print('Thread {} is running.'.format(self.i))
time.sleep(2)
return
print('Mian THread starting')
for i in range(1, 6):
t = myThread(i)
t.setDaemon(True)
t.start()
print('Mian THread end')
复制代码
运行截图如下:
我们可以在运行截图中看到,当我们使用setDaemon(True)方法,设置子线程为守护线程时,主线程一旦执行结束,则全部线程全部被终止执行,可能出现的情况就是,子线程的任务还没有完全执行结束,就被迫停止。 那么我们能不能让主线程等等我们的子线程,等待子线程运行结束后,主线程再终止呢,即实现守护线程相反的效果,答案是可以得。
阻塞线程 join()
import threading
import time
class myThread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
def run(self):
time.sleep(2)
print('Thread {} is running.'.format(self.i))
time.sleep(2)
return
print('Mian THread starting')
threads = []
for i in range(1, 6):
t = myThread(i)
t.start()
threads.append(t)
for t in threads:
t.join()
print('Mian THread end')
复制代码
运行截图如下:
我们可以看见主线程是在等待子线程运行结束才终止运行的,即
join()
所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程再终止。