本文共 6430 字,大约阅读时间需要 21 分钟。
在计算机科学中,进程、线程和协程是多任务执行模型的核心概念。这些概念在许多计算机应用中都有广泛的应用,特别是在操作系统和网络开发中。然而,有些人对这三个概念的区别并不明确,因此在这里,我将详细解释这些概念,并探讨它们的应用场景。
进程和线程都是操作系统中执行任务的基本单元,但它们有以下几个关键区别:
进程是:在执行的一个任务,由CPU执行。一个进程可以包含多个线程。
线程是:操作系统的最小调度单位。每个线程在执行时都会ContextHolder的CPU时间片。
进程和线程谁更快:进程无法比线程更快,因为线程是进程调度的基本单位。进程只能通过执行线程来获得并行执行。
启动进程和线程的区别:启动线程比启动进程快。启动线程时需要申请内存空间等资源,而启动进程直接执行指令。
内存空间:线程共享进程的内存空间,进程有独立的内存空间。
创建新线程与新进程:创建新线程比创建新进程简单,因为创建新进程需要复制父进程的内存空间。
操作权限:一个线程可以操作同一进程中的其他线程,而进程只能操作其子进程。
在操作系统中,线程切换通常通过时间片轮询机制实现。在单线程系统中,每个进程都有私有的虚拟地址空间,进程的所有线程共享同一地址空间。每个线程被CPU分配一个时间片。一旦线程运行完毕,它会被挂起,操作系统会切换到另一个线程继续执行。
这种轮询机制在多处理器系统中更为高效,因为它允许多个线程在多个CPU上同时运行。不过,即使在单处理器系统中,线程切换看起来也像是多线程同时在运行。
线程适用于需要大量I/O操作的任务,而不适用于需要高度并行化的CPU密集型任务。例如,网络服务器、文件处理和数据解析等任务通常可以通过线程实现来优化性能。
在Python中,线程是通过threading
模块实现的。以下是一个典型的线程创建示例:
import threadingdef run(name): print(name) time.sleep(2)threads = [threading.Thread(target=run, args=(i,)) for i in range(10)]for t in threads: t.start()
如上所示,可以通过threading.Thread
创建多个线程,并设置它们的目标函数和参数。在实际应用中,可以使用类实现线程,以便更好地管理线程的创建和执行。
主线程创建子线程后,子线程并不会阻碍主线程的执行。但如果不使用join
,主线程在结束后,子线程仍然会继续运行.join()
方法可以确保主线程等待子线程完成后再退出。
def run(name): for i in range(3): print(name, i) time.sleep(2)threads = [threading.Thread(target=run, args=('t%s' % i,)) for i in range(3)]for t in threads: t.start()for t in threads: t.join()print('main finished...')
默认情况下,主线程退出后,子线程仍然会继续执行。如果希望主线程退出后,子线程也退出,可以将子线程设置为守护线程:
import threadingdef run(name): for i in range(3): print(name, i) time.sleep(2)threads = [threading.Thread(target=run, args=('t%s' % i,)) for i in range(3)]for t in threads: t.setDaemon(True) t.start()print('main finished...')
在多线程环境中,同一时间只能有一个线程执行操作,因此需要使用同步机制来确保数据的一致性。Python的threading
模块提供了互斥锁(Lock
)和递归锁(RLock
)来实现线程同步。
import threadinglock = threading.Lock()num = 0def run(name): lock.acquire() global num num += 1 lock.release()threads = [threading.Thread(target=run, args=('t%s' % i,)) for i in range(10)]for t in threads: t.start()for t in threads: t.join()print('num:', num)
信号量是另一种线程同步机制,它指定了线程的最大数量,以确保一定数量的线程可以同时执行。可以使用multiprocessing.BoundedSemaphore
实现信号量。
import threadinglock = threading.BoundedSemaphore(3)def run(tag): lock.acquire() print(tag) time.sleep(2) lock.release()threads = [threading.Thread(target=run, args=('t%s' % i,)) for i in range(10)]for t in threads: t.start()for t in threads: t.join()print('main finished...')
线程可以通过事件来控制彼此的执行。事件可以用于实现线程间的通信和状态传递。
import threadingevent = threading.Event()def light(): count = 0 while True: if count < 5: event.set() print('\033[42;1m绿灯...%s\033[0m' % count) elif count > 4: event.clear() print('\033[41;1m红灯...%s\033[0m' % count) time.sleep(1) count += 1 if count == 10: count = 0thread_light = threading.Thread(target=light)thread_light.start()def car(): while True: if event.is_set(): print('绿灯了,我过马路咯') time.sleep(1) else: print('红灯了,等着过马路') event.wait()thread_car = threading.Thread(target=car)thread_car.start()
队列是一种高效的任务执行机制,允许多个任务同时等待队列中的数据。通过将任务放入队列,可以实现任务解耦,使程序间提高效率。
import queueq = queue.Queue(maxsize=2)q.put(1)q.put('domain')try: q.put('alex', block=False)except Exception as e: print(e)print(q.qsize())
生产者与消费者模式是一种解耦的任务执行机制,适用于资源有限的环境。生产者负责产生数据,消费者负责处理数据。
from queue import Queueq = Queue(maxsize=10)def produce(): count = 0 while True: q.put(count) print('产生%s' % count) count += 1 time.sleep(0.5)def consume(name): while True: data = q.get() time.sleep(1) print('%s消费了%s' % (name, data))thread_produce = threading.Thread(target=produce)thread_consume1 = threading.Thread(target=consume, args=('domain,))thread_consume2 = threading.Thread(target=consume, args=('alex',))thread_produce.start()thread_consume1.start()thread_consume2.start()
进程是操作系统的执行单元。一个进程可以包含多个线程,但每个进程都有自己的内存空间。
在Python中,可以使用multiprocessing
模块创建进程,并在进程中创建线程。
import threadingimport multiprocessingdef info(): print('parent process id:', multiprocessing.current_process().pid) print('current process id:', multiprocessing.current_process().pid)def run(): threads = [threading.Thread(target=info) for _ in range(2)] for t in threads: t.start() time.sleep(3)if __name__ == '__main__': info() processes = [multiprocessing.Process(target=run) for _ in range(1)] for p in processes: p.start() p.join() print('master process finished...')
进程间通信是通过共享内存或通过队列、管道等实现的。以下是一个简单的示例:
from multiprocessing import Queue, Processq = Queue()def fun(arg): arg.put('domain') arg.put('alex')if __name__ == '__main__': q = Queue() p = Process(target=fun, args=(q,)) p.start() print(q.get())
管道是一种简单的共享内存结构,可以用于进程间通信。
from multiprocessing import Process, Pipedef fun(child): child.send(['domain', 'alex']) child.send(['12', '33']) child.close()if __name__ == '__main__': parent, child = Pipe() p = Process(target=fun, args=(child,)) p.start() print(parent.recv()) print(parent.recv()) parent.send("from parent:hello") p.join()
进程池是一种固定数量的进程同时执行的方式,适合需要多次并发执行任务的场景。
from multiprocessing import Pool, osimport timedef run(arg): print('子进程:', os.getpid()) time.sleep(2) return os.getpid()if __name__ == '__main__': print('主进程id:', os.getpid()) pool = Pool(5) for i in range(20): if i % 2 == 0: pool.apply_async(func=run, args=(i,)) pool.close() pool.join() print('main finished...')
协程(协同可能线程,Greenlet)的概念类似于用户态的轻量级线程,它允许在单线程中实现并行执行。协程在Python中可以通过Greenlet库实现。
from greenlet import greenletdef func1(): print(1) g2.switch() print(2)def func2(): print(3) g1.switch() print(4)g1 = greenlet(func1)g2 = greenlet(func2)g1.switch()
gevent是一个增强版的Greenlet库,提供了更方便的API来实现协程。
import geventimport timedef func1(): print('在 func1 中,开始了。') gevent.sleep(2) print('在 func1 中,结束了。')def func2(): print('在 func2 中,开始了。') gevent.sleep(1) print('在 func2 中,结束了。')start_time = time.time()gevent.joinall([ gevent.spawn(func1), gevent.spawn(func2)])end_time = time.time()print(f'总耗时:{end_time - start_time}')
通过对比进程、线程和协程的概念,能够更好地理解它们在操作系统中的作用和应用场景。线程适用于需要大量I/O操作的任务,而进程适用于需要更大的资源隔离需求。协程则提供了一种轻量级的并行执行方式,特别适合I/O密集型任务。
转载地址:http://itltz.baihongyu.com/