Python进程和线程

python实现多任务有三种方式:进程、线程、协程。

进程

fork

#encoding=utf-8
import os
import time

pid = os.fork()
if pid == 0:         #新进程、子进程
    while True:
        print('唱歌')
        time.sleep(1)
else:                #主进程、父进程
    while True:
        print('跳舞')
        time.sleep(1)

#运行结果是同时产生
唱歌
跳舞
...

getpid(),getppid()

  • 主进程中os.getpid()和子进程中调用os.getppid()会得到同一个值。一般子进程的os.getpid() 比父进程的大,自增产生。
  • pid = os.fork() 在父进程中返回的值是子进程的id值,在子进程中返回0。
  • 父子进程谁先执行不确定。
  • 主进程结束,子进程不会结束,直到子进程自己结束

多进程中的全局变量: 多进程中,每个进程中所有数据(包括全局变量)都各自拥有一份,互不影响

多次fork

这里写图片描述
在某个进程里调用fork,则只会多出一个进程。

import os
pid = os.fork()
if pid == 0:
    print('child process %d'%(os.getpid()))
else:
    print('parent process %d'%(os.getpid()))
    pid = os.fork()
    if pid == 0: 
        print('child process 2 %d'%(os.getpid()))
    else:
        print('parent process 2 %d'%(os.getpid())

#打印结果:
parent process 39763
parent process 2 39763
child process 39800
child process 2 39801

fork炸弹

while True:
    fork()

multiprocessing模块

fork在Windows平台不可用,multiprocessing模块是Python提供的跨平台的的多进程的支持。

from multiprocessing import Process

def test():
    print('')

p = Process(target=test)
p.start()   #让这个进程执行test函数的代码

Process创建子进程,主进程会等待所有的子进程结束后自己才结束,和fork()是不一样的。

join子进程

from multiprocessing import Process

def test():
    print('------test-------')

p = Process(target=test)
p.start()
p.join([timeout])   #等待子进程结束[多少秒]后继续往下走
print('------main-------')

常用Process方法:
start() , join() , terminate()

Process子类

另外一个创建子进程的方法:

class ChildClass(Process):
    def __init__(self):
        pass
    #start()后会自动调用run方法
    def run(self):
        pass

if __name__ == '__main__':
    cc = ChiildClass()
    cc.start()
    cc.join()

进程池Pool

又是另一种创建子进程的方式。

#coding=utf-8
from multiprocessing import Pool
import os

def work(n):
    print('----work--->%d-----%d-------'%(n,os.getpid()))

po = Pool(3)
for i in range(10):
    #po.apply(work,(i,))  #以堵塞方式添加任务。几乎不用
    po.apply_async(work,(i,))

po.close()  #关闭Pool,使之不再接受新的任务
po.join()   #必须等待所有子进程执行完成才结束,必须放在close方法后。否则,主进程马上就结束了

执行结果
----work--->0-----43452-------
----work--->1-----43452-------
----work--->2-----43452-------
----work--->3-----43452-------
----work--->5-----43452-------
----work--->6-----43452-------
----work--->7-----43452-------
----work--->8-----43452-------
----work--->9-----43452-------
----work--->4-----43453-------

进程间通信-Queue

用Queue可以实现进程间的数据共享

#coding=utf-8
from multiprocessing import Queue

q = Queue(3)
print(q.empty())    #True
q.put('123')  #使用之前判断是否full
q.put('345')
q.put('222')

print(q.full())   #False
print(q.get())   #使用之前使用empty判断
print(q.full())   #True

q.get()相当于q.get(True)   阻塞读取
q.get_nowait相当于 q.get(False)
put类似

进程池之间的Queue

#coding=utf-8
from multiprocessing import Manager,Pool
import os

def reader(q):
    print('reader启动(%s),父进程-%s'%(os.getpid(),os.getppid()))
    for i in range(q.qsize()):
        print('reader从Queue获取消息:%s'%q.get(True))

def writer(q):
    print('writer启动(%s),父进程-%s'%(os.getpid(),os.getppid()))
    for i in 'bendeng':
        q.put(i)

if __name__ == "__main__":
    print('进程-%s start'%os.getpid())
    q = Manager().Queue()
    po = Pool()
    po.apply(writer,(q,))
    po.apply(reader,(q,))
    po.close()
    po.join()
    print('进程-%s End'%os.getpid())

线程

#coding=utf-8
from threading import Thread
def test():
    print('test')

for i in range(5):
    t = Thread(target=test)
    print(t.getName())
    t.start()
#执行结果
Thread-1
test
 Thread-2
Thread-3
 test
test
 Thread-4
test
Thread-5
test
  • 和进程类似,也可以使用Thread子类实现多线程
#coding=utf-8
import threading

class MyThread(threading.Thread):
    def run(self):
        for i in range(5):
            print(self.name)


if __name__ == "__main__":
    t = MyThread()
    t.start()

主线程会等待子线程结束后才结束。多线程执行是无序的。
PS:0号进程负责切换进程,1号进程负责生成进程。孤儿进程也是被1号进程收容。

  • 多线程中的全局变量
    全局变量在多线程中是共享的。但全局变量在多线程中有可能是不准确的。于是产生了同步的问题。

同步-互斥锁

使用Lock来处理多线程处理全局变量的问题

#coding=utf-8
from threading import Thread,Lock

g_n = 0

def test1():
    global g_n
    #print(threading.current_thread())
    mutex.acquire()  #上锁
    for i in range(1000000):
        g_n += 1
    mutex.release()  #解锁
    print('test1_g_n=%d'%(g_n))


def test2():
    global g_n
    #print(threading.current_thread())
    mutex.acquire()  #上锁
    for i in range(1000000):
        g_n += 1
    mutex.release()  #解锁
    print('test2_g_n=%d'%(g_n))

#创建一个互斥锁,默认是不上锁的
mutex = Lock()

t1 = Thread(target=test1)
t1.start()

t2 = Thread(target=test2)
t2.start()

print('g_n=%d'%(g_n))

两个线程执行同一个函数,函数里面的变量(非共享数据)也是独立的,互不影响。

死锁

在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
避免死锁的方法:

  • 程序设计时要尽量避免(银行家算法)
  • 添加超时时间

同步

同步就是协同步调,按预定的先后次序进行运行。
lock2.acquire -> lock1.release
lock1.acquire -> lock3.release
lock3.acquire -> end

生产者与消费者模式

阻塞队列是用来生产者和消费者来解耦的。

ThreadLocal

多线程中处理局部变量的问题。

#coding=utf-8
import threading

thread_local = threading.local()

def process():
    obj = thread_local.obj
    print('handle %s (in %s)'%(obj,threading.currentThread()))

def process_thread(name):
    thread_local.obj = name
    process()


t1 = threading.Thread(target=process_thread,args=("ben",),name='Thread-A')
t2 = threading.Thread(target=process_thread,args=("deng",),name='Thread-B')
t1.start()
t2.start()

t1.join()
t2.join()
#执行结果
handle ben (in <Thread(Thread-A, started 123145532739584)>)
 handle deng (in <Thread(Thread-B, started 123145536946176)>)

异步

子进程结束,主进程接着做下一个事情。

#coding=utf-8
from multiprocessing import Pool
import time,os

def test1():
    print('进程中的进程---pid=%d,ppid=%d'%(os.getpid(),os.getppid()))
    for i in range(3):
        time.sleep(1)

    return 'test1 return'

def test2(args):
    print('callback------pid=%d'%(os.getpid()))
    print('callback args=%s'%args)

po= Pool(3)
po.apply_async(func=test1,callback=test2)

po.close()
po.join()

time.sleep(3)
print('主进程id=%d'%(os.getpid()))

#执行结果:
进程中的进程---pid=68912,ppid=68911
callback------pid=68911
callback args=test1 return
主进程id=68911

GIL

GIL全名全局解释器锁。在Python中,多线程是假的,在多核CPU的情况下,多线程使用了一个叫GIL 的变量控制了一个线程只能占用一核CPU。

from threading import Thread

def deadloop():
    while True:
        pass

t = Thread(target = deadloop)#lib.DeadLoop
t.start()

#main thread also deadloop
while True:
    pass

结果双核CPU使用率并没有到100%。使用htop命令查看。
这里写图片描述

所以在Python中,多进程比多线程效率高[多核]。
解决方案:
1、能用线程用进程
2、使用C语言解决。

from ctypes import *
from threading import Thread

#load c lib
lib = cdll.LoadLibrary("./libdeadloop.so")

t = Thread(target = lib.DeadLoop)
t.start()

#main thread also deadloop
#lib.DeadLoop()
while True:
    pass

C语言代码如下:

//一个死循环
void DeadLoop(){
    while(1){
        ;
    }
}

在Linux系统中使用命令gcc xxx.c -shared -o libxxxx.so将c文件编译成一个动态库文件。

然后运行情况如下:
这里写图片描述
双核CPU的使用率都达到了100%!

从Ubuntu安装Sublime Text3

1、添加Sublime-text-3软件包的软件源

sudo add-apt-repository ppa:webupd8team/sublime-text-3

2、使用以下命令更新系统软件源

sudo apt-get update

3、使用以下命令安装Sublime-text-3

sudo apt-get install sublime-text-installer

4、最后可在Dash Home中见到Sublime-text的软件图标,点击就可使用了.

  • 从命令行启动
subl
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值