(XWZ)的python学习笔记Ⅵ——进程和线程

进程和线程

多进程

Process

在python中,我们可以通过实例化multiprocessing模块中的Process类来创建一个子进程,需要给该该进程传入需要执行的函数和对应的参数。进程创建好后使用方法start()来启动,在父进程中使用方法jion()时,父进程会等待子进程执行完后再接着往下执行,同于实现进程的同步操作。来看个栗子就知道怎么操作了:

from multiprocessing import Process
import os

def fun(msg):
    print('子进程开始...')
    print('我是进程%s, 正在执行任务%s。父进程是%s' % (os.getpid(), msg, os.getppid()))
    print('子进程结束...')

if __name__ == '__main__':
    print('父进程开始...')
    print('父进程号是%s' % os.getpid())
    p = Process(target = fun, args = ('A',))
    p.start()
    p.join() #在此处等待子进程执行完再接着往下执行
    print('父进程结束...')

运行结果为:
父进程开始…
父进程号是12096
子进程开始…
我是进程11724, 正在执行任务A。父进程是12096
子进程结束…
父进程结束…

Pool

除了使用Process可以创建子进程,我们还可以使用Pool来创建出多个子进程,称为进程池。Pool中创建并启动进程有两种方法——apply()apply_async(),这两个方法也需传入要执行的函数和对应参数。apply()方式启动的进程是串行执行的,效率低,而apply_async()是并发执行的,效率高,因此推荐使用后者!Pool有个close()方法,调用了close()后就不能添加新的进程了,同时也有个join()方法用于实现进程的同步,这里要注意,调用join()之前必须先调用close(),主进程结束后程序(子进程会强制结束)就会退出。来看个例子:

from multiprocessing import Pool
import os

def fun(msg):
    print('task %d: process %s is running and parents process is %s' % (msg, os.getpid(), os.getppid()))

if __name__ == '__main__':
    print('process %s starts to run' % os.getpid())
    ps = Pool(5)
    for i in range(7):
        #ps.apply(fun, args = (i,))
        ps.apply_async(fun, args = (i,))
    ps.close()
    ps.join()
    print('process %s ends' % os.getpid())

运行结果为:
process 7036 starts to run
task 0: process 8516 is running and parents process is 7036
task 1: process 8516 is running and parents process is 7036
task 2: process 8516 is running and parents process is 7036
task 3: process 12132 is running and parents process is 7036
task 4: process 11680 is running and parents process is 7036
task 5: process 12132 is running and parents process is 7036
task 6: process 8516 is running and parents process is 7036
process 7036 ends

多线程

  • 一个进程至少包含一个线程,线程之间是并发执行的,因此执行效率较高。python中使用threading模块来操作线程。先创建Thread实例,然后调用start()开始执行,threading.current_thread()函数是获得当前线程的实例,主线程实例的名字叫MainThread,子线程的名字在创建时指定,如果不起名字Python就自动给线程命名为Thread-1,Thread-2……,来看个例子:
import threading, time
#新线程中要执行的函数
def fun():
    bgn = time.time()	#获得此刻的时间戳
    print('线程%s开始运行...' % threading.current_thread().name)
    it = (x for x in range(10) if x % 2)
    for x in it:
        print('线程%s产生数据:%d' % (threading.current_thread().name, x))
        time.sleep(1)
    end = time.time()
    print('线程%s运行结束!运行时间为%fs' % (threading.current_thread().name, end - bgn))

bgn = time.time()
print('主线程开始运行...')
t = threading.Thread(target = fun, name = 'funThread')
t.start()
it = (y for y in range(10) if not y % 2)
for y in it:
    print('主线程产生数据: %d' % y)
    time.sleep(1)
end = time.time()
print('主线程运行结束!运行时间为%fs' % (end - bgn))

运行结果为:
主线程开始运行…
线程funThread开始运行…
主线程产生数据: 0
线程funThread产生数据:1
线程funThread产生数据:3
主线程产生数据: 2
线程funThread产生数据:5
主线程产生数据: 4
线程funThread产生数据:7
主线程产生数据: 6
主线程产生数据: 8
线程funThread产生数据:9
主线程运行结束!运行时间为5.023202s
线程funThread运行结束!运行时间为5.022726s

  • 一个进程的多个线程能够共享变量,因此在操作多线程时需要解决的一个问题是互斥资源的访问,即互斥资源在每次只能由一个线程进行访问,否则就会出现问题,比如看下面的例子:
import threading


money = 0

def chance_money(n):
    global money
    for i in range(100000000):
        money = money + n
        money = money - n
    
t1 = threading.Thread(target = chance_money, args = (5,))
t2 = threading.Thread(target = chance_money, args = (10,))
t1.start()
t2.start()
t1.join()
t2.join()
print('money = %d' % money)

上述代码中,我们每次在加n之后又减n,所以按理说最后得到的money应该是0才对,但最后输出的结果是money = -80。这是因为在给money赋完值后还没来得及进行下一步就被另一个线程中money的赋值给覆盖了。为了解决这个问题,我们就需要给临界区代码上锁,python中使用threanding.lock()来获得一个锁,然后将临界区代码夹在acquire()release()方法中:

import threading

money = 0
lock = threading.Lock()

def chance_money(n):
    global money
    lock.acquire() #给临界区上锁
    for i in range(100000000):
        money = money + n
        money = money - n
    lock.release() #释放锁
t1 = threading.Thread(target = chance_money, args = (5,))
t2 = threading.Thread(target = chance_money, args = (10,))
t1.start()
t2.start()
t1.join()
t2.join()
print('money = %d' % money)

这样就能保证每次只有获得锁的那个线程才能够修改互斥资源money,现在就不会出现问题了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值