欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python学习之旅(二十三)

程序员文章站 2022-09-14 08:50:07
Python基础知识(22):进程和线程(Ⅰ) 1、多进程 (1)fork Python的os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程 fork可以在Mac的Python上运行,但无法再Windows下运行 (2)multiprocess multipro ......

python基础知识(22):进程和线程(ⅰ)

1、多进程

(1)fork

python的os模块封装了常见的系统调用,其中就包括fork,可以在python程序中轻松创建子进程

fork可以在mac的python上运行,但无法再windows下运行

(2)multiprocess

multiprocessing模块就是跨平台版本的多进程模块

multiprocessing模块提供了一个process类来代表一个进程对象

#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()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步

(3)pool

用进程池的方式批量创建子进程,启动大量的子进程

#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核数为1

(4)子进程

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()方法

(5)进程间通信

python的multiprocessing模块包装了底层的机制,提供了queuepipes等多种方式来交换数据

#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的标准库提供了两个模块:_threadthreading_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-1thread-2……

lock

线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改

线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了

当某个进程要更改数据时,先给它上锁,其它线程不能更改。只有当锁被释放后,其它线程获得该锁以后才能改

由于锁只有一个,无论多少线程,同一时刻最多只有一个线程持有该锁,所以,不会造成修改的冲突

多核cpu

python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务。多个python进程有各自独立的gil锁,互不影响