python线程和进程

多进程:

启动一个程序后就会自动创建一个进程,可以在该进程的基础上创建一些子进程来完成任务

创建进程:
1)Process创建进程:

利用multiprocessing模块创建进程,Process(target =funtion,args=()):

from   multiprocessing import Process
import os

def function(say):
    print('%s now the child porcess ID is %s and my father process id is %s' %(say,os.getpid(),os.getppid()))

if __name__ =='__main__':
    print('this is father process and the id is %s' %os.getpid())
    process_test =Process(target=function,args=('hello',))
    process_test.start()
    process_test.join()

output:

this is father process and the id is 8880
hello now the child porcess ID is 5724 and my father process id is 8880

join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。

2)利用Pool批量创建子进程

def function(say):
    print('%s now the child porcess ID is %s and my father process id is %s' %(say,os.getpid(),os.getppid()))

if __name__ =='__main__':
    print('this is father process and the id is %s' %os.getpid())
    p =Pool(4)
    for i in range(4):
     p.apply_async(function,args=(i,))
     time.sleep(1)
    p.close()
    p.join()

Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process

output:

this is father process and the id is 20624
0 now the child porcess ID is 13072 and my father process id is 20624
1 now the child porcess ID is 19864 and my father process id is 20624
2 now the child porcess ID is 13072 and my father process id is 20624
3 now the child porcess ID is 11720 and my father process id is 20624
进程间通信

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

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()
        print('get %s from queue' % value)
if __name__ =='__main__':
    q =Queue()
    pw = Process(target=write,args=(q,))
    pr = Process(target=read,args=(q,))
    pw.start()
    pr.start()
    pw.join()
    pr.terminate()

output:

process to read 10324
Process to write 17308
put A to queue
get A from queue
put B to queue
get B from queue
put C to queue
get C from queue

多线程:

多任务可以由多进程完成,也可以由一个进程内的多线程完成,进程是由若干个线程组成的,一个进程至少有一个线程

如何创建并启动一个线程:

theading.Thread(target=function_name,name='thread_name',args=())的方法来创建一个线程(如果不指定线程的名字,那么python将会分配默认的线程名字Thread-1 2 3..),用start启动、用join关闭,在进程启动的时候就会启动一个名为MainThread的主线程,没有新建其他线程的时候,进程内运行的只有这个线程

def threadtest():
    print('now the thead name is %s' %threading.current_thread().name)
    for i in range(0,5):
        print(i)
    print('now the thread name is still %s' %threading.current_thread().name)

print('the thread %s is running' %threading.current_thread().name)
thead_test =threading.Thread(target=threadtest,name='wdp_thread')
thead_test.start()
thead_test.join()
print('now it is thread %s' %threading.current_thread().name)

output

the thread MainThread is running
now the thead name is wdp_thread
0
1
2
3
4
now the thread name is still wdp_thread
now it is thread MainThread

要注意使用多线程时共享变量的问题,操作系统学过的是知识,两个线程同时对一个共享变量进行处理,产生的结果可能有多少种。为了避免这种情况发生,python中使用线程时会用锁

def run_thread(n):
    for i in range(100000):
        # 先要获取锁:
        lock.acquire()
        try:
            change_it(n)
        finally:
            # 改完了一定要释放锁:
            lock.release()

多个线程同时执行lock.acquire()时只有一个线程可以成功获得锁,获得锁的线程用完一定要释放,否则等待锁的线程永远得不到锁从而无法执行,成为死线程。

锁的好处就是确保了某段关键代码只能由一个线程从头到尾完整地执行,坏处当然也很多,首先是阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。其次,由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁,导致多个线程全部挂起,既不能执行,也无法结束,只能靠操作系统强制终止。

ThreadLocal

即线程的局部变量,线程的局部变量只有线程自己能看得到,很安全,但是如果要想被线程内部的函数调用就必须将该变量放在函数的参数里,这样很麻烦,比如下面,

class Student(object):
    def __init__(self,name):
        self.name =name

def process_student(name):
    std =Student(name)
    stuwrite(std)
    stusay(std)

def stuwrite(std):
    print('%s is writing'%std.name)
def stusay(std):
    print('%s is saying'%std.name)

process_student('bob')

stuwritestusay方法中,要想得到std的名字,都需要吧std作为参数传入这两个方法中,每次都要传入std显得很麻烦,一种解决方法是,用一个dict存储当前的线程名作为key,其中的局部变量作为vaue,那么在函数中使用这些变量的时候就不需要通过传递参数,直接通过字典查询就可以了。

把上述思路简化就成了python线程中的ThreadLocal,不用查找dictThreadLocal帮你自动做这件事:

local_student =threading.local()
def process_student():
    std =local_student.student
    print('student %s run in thread %s'%(std,threading.current_thread().name))

def process_thread(name):
    local_student.student =name
    process_student()

t1 =threading.Thread(target=process_thread,args=('bob',),name='Thread_A')
t2 =threading.Thread(target=process_thread,args=('alice',),name='Thread_B')
t1.start()
t2.start()
t1.join()
t2.join()

output:

student bob run in thread Thread_A
student alice run in thread Thread_B

使用了threading.local后,线程之间的变量肯定不会混淆的,在某一个线程中的不同函数里可以任意调用局部变量,只要该变量加入了threading.local中,而不是通过把变量当做参数传递到函数内才能被调用。

猜你喜欢

转载自blog.csdn.net/dpengwang/article/details/81659973