前言:本系列将包含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()所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程再终止。