1.1 并发与并行基本概念
- 并发concurrency,同时做某些任务,强调一段时间内要处理的任务;
- 并行parallel,同时做某些任务,强调同一时刻可以互不干扰加粗样式地同时执行某些任务。
1.2 进程和线程
1.2.1 概念理解
-
进程:
程序是源代码编译后的文件,当程序执行的时候,会被加载到内存中,而在内存中运行的程序就是进程,即一个程序的执行实例就是一个进程,它是计算机中程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。每一个进程都认为自己独占所有的计算机硬件资源,好比一个独立的国家,一般进程间不可以随便共享数据; -
线程:
线程是操作系统能够进行运算调度的最小单位,被包含在进程中,是进程中的实际运作单位;同一个进程内的线程可以共享进程的资源,好比一个国家的省份,可以共享国内政策,每一个线程拥有自己独立的堆栈,即线程之间一般是不可以互相访问各自内部的资源的。 -
总结:
进程用来占用资源,占用来的资源分给线程进行调度使用,进程好比国家,一般不可以随便共享资源,线程好比省份,可以共享进程的资源,但是各个线程又是独立的堆栈,内部资源一般不可以互相访问。
1.2.2 线程的状态
1.3 python中的线程
1.3.1 标准库threading
python中的线程开发使用标准库threading,进程靠线程执行代码,至少有一个主线程,其他线程是工作线程,主线程是第一个启动的线程,即从上到下代码执行的那个线程,工作线程是在主线程执行的基础上进行分支并行执行的。
1.3.2 线程的使用
import threading
def worker():
print('I am working')
print('Finished')
t = threading.Thread(target=worker, name='线程名字', args=(), kwargs=None, *, daemon=None)
t.start()
名称 | 作用 |
---|---|
threading.Thread() | 首先创建线程对象 |
target | 线程调用的对象,用来指向目标函数对象 |
name | 指定线程的名称,可以重复 |
args | 为目标函数传递可变参数,接收多个参数,封装为元组 |
kwargs | 可变关键字传参,字典 |
daemon | 守护线程,决定工作线程是否跟随主线程消亡,True为跟随 |
线程对象.start() | 启动线程 |
python中未提供线程退出的方法,要么线程函数执行完毕,要么线程函数中抛出异常。
线程的传参本质和函数传参没什么区别。
1.3.2 threading对象的属性和方法
名称 | 作用 |
---|---|
name | 通过线程对象.name显示线程的名字,可重复 |
ident | 线程对象属性,返回线程ID(唯一),非0整数,只有线程启动后才有ID,否则未None,线程退出,此ID依然可以访问 |
is_alive() | 判断线程是否活着 |
start() | 启动线程,每个线程必须且只能执行一次该方法 |
run() | 运行线程函数,相当于函数调用 |
isDaemon() | 是否是daemon线程 |
setDaemon() | 设置为daemon线程,必须在start()方法之前 |
join(timeout=None) | 用来等待另一个线程 |
-
start和run方法:
start()方法会调用run()方法,run()方法可以运行函数,start方法启动一个新的线程,然后调用run()方法进行目标函数调用,而run方法并没有启动新的线程,就是主线程中调用了一个普通的函数。 -
守护线程:
决定着是否跟着主线程结束而结束,可手动设置True或False,也可不设置,默认为None。主线程是non-daemon线程,python程序中在没有活着的non-daemon线程运行时,程序退出,即除主线程之外剩下的只能都是daemon线程,主线程才能退出,否则主线程只能等待。 -
join()
join(timeout=None),是线程的标准方法之一。一个线程中调用另一个线程的join方法,调用者将被阻塞,直到被调用线程终止。一个线程可以被join多次。
timeout指定调用者需要等待多久,未设置则一直等待,调用谁的join方法,就是join谁,就要等谁。
1.3 多线程中的输出
一个进程中如果有多个线程运行,就是多线程,实现一种并发
1.3.1 线程安全
print()函数分为两步,第一步打印内容,第二步打印换行符,在多线程中会发生线程切换,print()函数会被打断,所以print函数是线程不安全的(即执行一段代码,结果未达到预期结果)
解决方法:
1.不让print()函数打印换行
2.使用logging,日志处理模块,线程安全
logging配置:
import logging
fmtstr = "%(asctime)s %(threadName)s %(thread)s %(message)s"
logging.basicConfig(level=logging.INFO, format=fmtstr)
logging.info(内容) # 使用打印,message即为打印的内容