Python的os
模块封装了常见的系统调用,其中就包括fork
,能够在Python程序中轻松建立子进程python
fork能够在Mac的Python上运行,但没法再Windows下运行多线程
multiprocessing
模块就是跨平台版本的多进程模块app
multiprocessing
模块提供了一个Process
类来表明一个进程对象dom
#process_1.py from multiprocessing import Process import os def work(name): print("Run child process %s(%s)..." %(name,os.getpid())) if __name__=="__main__": print("Parent process %s." % os.getpid()) #建立进程实例 p = Process(target=work, args=("test",)) print("Child process will start...") p.start() p.join() print("Child process end.") 结果: Parent process 14628. Child process will start... Child process end.
建立子进程时,只须要传入一个执行函数和函数的参数,建立一个Process
实例,用start()
方法启动,join()
方法能够等待子进程结束后再继续往下运行,一般用于进程间的同步async
用进程池的方式批量建立子进程,启动大量的子进程函数
#process_2.py from multiprocessing import Pool import os, time, random def long_time_task(name): print("Run task %s(%s)..." %(name,os.getpid())) start=time.time() time.sleep(random.random()*3) end=time.time() print("Task &s runs %0.2f seconds." %(name,(end - start))) if __name__=="__main__": print("Parent process %s." % os.getpid()) p = Pool(2) for i in range(3): p.apply_async(long_time_task, args=(i,)) print("Waiting for all subprocess done...") p.close() p.join() print("All subprocess done") 结果: Parent process 2096. Waiting for all subprocess done... All subprocess done
Pool
的默认大小是CPU的核数,这次运行环境cup核数为1spa
subprocess
模块可让咱们很是方便地启动一个子进程,而后控制其输入和输出线程
#process_3.py import subprocess print("$ nslookup www.python.org") r = subprocess.call(["nslookup", "www.python.org"]) print("Exit code:", r) 结果: $ nslookup www.python.org Exit code: 0
若是子进程还须要输入,则能够经过communicate()
方法code
Python的multiprocessing
模块包装了底层的机制,提供了Queue
、Pipes
等多种方式来交换数据对象
#process_4.py from multiprocessing import Process, Queue import os, time, random def write(q): print("Process to write: %s" %os.getpid()) for value in ["A","B","C"]: print("Put %s to queue..." % value) q.put(value) time.sleep(random.random()) def read(q): print("Process to read: %s" % os.getpid()) while True: value = q.get(True) print("Get %s from queue." % value) if __name__=="__mainn__": q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) pw.start() pr.start() pw.join() pr.terminate()
多任务能够由多进程完成,也能够由一个进程内的多线程完成
进程是由若干线程组成的,一个进程至少有一个线程
Python的标准库提供了两个模块:_thread
和threading
,_thread
是低级模块,threading
是高级模块,对_thread
进行了封装
绝大多数状况下,咱们只须要使用threading
这个高级模块
import time, threading def work(): n = 1 while n < 6: print("Work %s is running..." % str(n)) n+=1 t = threading.Thread(target = work, name = "workThread") t.start() t.join() print("%s ended." % threading.current_thread().name) 结果: Work 1 is running... Work 2 is running... Work 3 is running... Work 4 is running... Work 5 is running... MainThread ended.
因为任何进程默认就会启动一个线程,咱们把该线程称为主线程,主线程又能够启动新的线程,Python的threading
模块有个current_thread()
函数,它永远返回当前线程的实例
主线程实例的名字叫MainThread
,子线程的名字在建立时指定,名字仅仅在打印时用来显示,彻底没有其余意义,若是不起名字Python就自动给线程命名为Thread-1
,Thread-2
……
线程中,全部变量都由全部线程共享,因此,任何一个变量均可以被任何一个线程修改
线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了
当某个进程要更改数据时,先给它上锁,其它线程不能更改。只有当锁被释放后,其它线程得到该锁之后才能改
因为锁只有一个,不管多少线程,同一时刻最多只有一个线程持有该锁,因此,不会形成修改的冲突
Python虽然不能利用多线程实现多核任务,但能够经过多进程实现多核任务。多个Python进程有各自独立的GIL锁,互不影响