引入
生活中,我们在电脑上打开了一个word, 这个word对操作系统来说就是一个进程。我们在进行word操作的时候,比如在你打字的时候,该word同时可以进行文字检查。发现了没,在同一个进程中,我们也可以进行同时操作。这就带来了线程的概念。在一个进程中,要同时干多件事,就需要同时运行多个“子任务”,我们把这些子任务可以叫做线程。
线程出现的背景及意义
线程的出现和意义可以从几个方面来理解,主要包括计算机历史背景的发展、效率和资源管理的需要、以及对并发编程模型的追求。
计算机历史背景
早期的计算机系统大多是单任务的,即计算机在任何时刻只能执行一个任务。随着计算机技术的发展,人们对计算机的处理能力和效率提出了更高的要求,这促使操作系统向多任务系统发展。在多任务操作系统中,多个任务(进程)可以共享CPU时间,使得计算机资源得到更有效的利用。
效率和资源管理
进程作为操作系统资源分配和调度的基本单位,拥有独立的地址空间和系统资源。这种设计在隔离性和安全性方面有显著优势,但进程的创建、销毁和切换代价较高,资源开销大。为了减少这种开销,提高系统的并发性和响应速度,线程被引入作为轻量级的进程。
线程(有时被称为轻量级进程)共享同一进程的地址空间和资源,但拥有独立的执行路径和栈空间。这种设计使得线程的创建、销毁和切换的开销远小于进程,从而大大提高了系统的效率。
对并发编程模型的追求
随着多核处理器的出现和发展,利用并发和并行编程模型来充分利用多核处理器的计算能力变得尤为重要。线程作为实现并发执行的基本单位,使得开发者可以更容易地编写出能够充分利用多核处理器性能的程序。
线程不仅可以在多核处理器上并行执行,提高程序的执行效率,而且在单核处理器上也能通过时间分片技术实现并发执行,提高响应速度和资源利用率。此外,线程还支持更细粒度的任务划分和更灵活的控制,有助于实现复杂的并发编程模型,如响应式编程、事件驱动编程等。
总结
线程的出现主要是为了提高程序的执行效率和响应速度,减少操作系统在任务管理上的开销,并更好地利用多核处理器的计算能力。线程使得并发和并行编程成为可能,为开发高性能、高响应速度的应用程序提供了基础。
关键概念和术语
Python中的多线程编程涉及到一系列的概念和术语。下面列出了一些关键概念,以及如何使用threading
模块进行多线程编程的基本示例。
-
线程(Thread): 是程序执行中一个单一的顺序控制流程,线程是操作系统处理器能够进行运算调度的最小单位。它被包含在进程之中,一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间),是进程中的实际运作单位。在Python中,
threading
模块允许我们创建和管理线程。 -
主线程(Main Thread):Python程序启动时,默认会创建一个线程,称为主线程。程序中的所有代码默认都在主线程中执行,除非显式地创建新的线程。
-
子线程(Child Thread):通过程序创建的新线程称为子线程。程序可以同时运行多个子线程,以执行并行操作。
-
线程同步(Thread Synchronization):当多个线程需要共享数据或资源时,需要确保这些共享资源不会同时被多个线程修改,以避免数据不一致或状态混乱的问题。常用的线程同步机制包括锁(Locks)、事件(Events)、条件(Conditions)等。
-
死锁(Deadlock):当两个或多个线程在等待对方释放资源,而这些资源又被对方占用时,会导致这些线程无限等待,发生死锁。
多进程和多线程的区别
- 多线程可以共享全局变量,多进程不能。
- 多线程中,所有子线程的进程号相同;多进程中,不同的子进程进程号不同。
- 线程共享内存空间;进程的内存是独立的
- 同一个进程之间的线程可以直接通信,而两个进程之间的通信需要代理
- 一个线程可控制和操作同一进程里的其它线程,进程只能操作子进程
- 在多进程中,同一个变量,各自有一份拷贝存在于每一个进程中,互不影响;而多线程中,所有的变量都有线程共享。
参考:https://www.cnblogs.com/qianqiannian/p/7010909.html
常用代码示例
创建和启动线程
import threading
def thread_function(name):
print(f"Thread {name} is running")
if __name__ == "__main__":
# 创建线程
my_thread = threading.Thread(target=thread_function, args=("MyThread",))
# 启动线程
my_thread.start()
# 等待线程完成
my_thread.join()
print("Main : all done")
使用锁进行线程同步
import threading
# 创建一个锁
lock = threading.Lock()
def thread_function(name):
lock.acquire() # 获取锁
try:
print(f"Thread {name} is running")
finally:
lock.release() # 释放锁
if __name__ == "__main__":
for i in range(5):
my_thread = threading.Thread(target=thread_function, args=(i,))
my_thread.start()
my_thread.join() # 注意:在实际应用中,通常不会在这里立即调用join()
使用with
语句简化锁的操作
import threading
# 创建一个锁
lock = threading.Lock()
def thread_function(name):
with lock:
print(f"Thread {name} is running")
if __name__ == "__main__":
for i in range(5):
my_thread = threading.Thread(target=thread_function, args=(i,))
my_thread.start()
my_thread.join()
注意事项
- 全局解释器锁(GIL):由于Python的全局解释器锁(GIL),在CPython解释器中,即使在多核处理器上,同一时刻只能有一个线程执行Python字节码。这意味着,对于CPU密集型任务,使用多线程并不能达到理想的并行效果。在这种情况下,可以考虑使用多进程(
multiprocessing
模块)来实现真正的并行计算。 - I/O密集型任务:对于I/O密集型任务(例如文件读写、网络请求等),多线程可以有效提高程序性能,因为线程可以在等待I/O操作完成时让出CPU,执行其他任务。