Python之路PythonThread,第四篇,进程4

python3  进程/线程4

 进程间同步互斥方法:

from multiprocessing import Lock

创建 进程锁对象

lock = Lock()

lock.acquire()  给临界区上锁

lock.release() 给临界区解锁

说明:1,具体实现上 acquire() 为一个条件阻塞函数;

           2,当有任意一个进程先进行了acquire操作后,其他进程再企图进行acquire操作时就会阻塞,直到lock对象被release后其他进程CIA可以进行下次

                acquire操作;

with lock: 也可以实现加锁,解锁

 

线程:

1,线程也可以使用计算机的多核资源,也是多任务编程方式之一;

2, 线程又称为轻量级的进程,在并发上和进程相同,但是在创建时销毁资源少;

说明:1,一个进程中可以包含多个线程,这个多个线程共享进程的资源;

            2, 多个线程因为共享进程的资源,所以在通信上往往采用全局变量的方式;

            3,线程也有自己特有的资源,比如TTD指令集等;

多进程和多线程的区别和联系:

1,多进程和多线程都是多任务编程方式,都可以使用计算机多核;

2,进程的创建要比线程消耗更多的资源;

3,进程的空间独立数据更安全,有专门的进程间通信方式进行交互;

4,一个进程包含多个线程,所以线程共享进程资源,没有专门的通信方式,依赖全局变量进行通信。 往往需要使用同步互斥机制,逻辑需要考虑更多;

5,进程线程都有自己特有的资源,多个关联任务的时候使用多线程资源消耗更少; 如果是多个无关联任务也不适用全部都使用线程;

 1 from multiprocessing import Process,Lock
 2 import time,sys 
 3 
 4 def worker1(stream):
 5     lock.acquire() # 加锁
 6     for i in range(5):
 7         time.sleep(1)
 8         stream.write("Lock acquired via\n")
 9     lock.release()#解锁
10 
11 def worker2(stream):
12     # lock.acquire()
13     with lock:    #加锁 语句块结束即解锁
14         for i in range(5):
15             time.sleep(1)
16             stream.write("Lock acquired directly\n")
17     # lock.release()
18 
19 lock = Lock()
20 #sys.stdout为所有进程都拥有的资源
21 w1 = Process(target=worker1,args=(sys.stdout,))
22 w2 = Process(target=worker2,args=(sys.stdout,))
23 
24 w1.start()
25 w2.start()
26 
27 w1.join()
28 w2.join()
View Code

 

 创建线程:

import  threading

创建线程函数

threading.Tread()

功能:创建线程

参数:target     线程函数

            args      以元组方式给线程函数传参

            kwargs    以字典方式给线程函数传参

            name      线程名称(默认Thread-1)

返回值:返回线程对象

线程属性和方法:

t.start()        启动一个线程

t.is_alive()    查看一个线程的状态

t.name         查看线程的名称

t.join([esc])   阻塞等待回收线程

 1 import threading 
 2 from time import ctime,sleep 
 3 
 4 a = 10
 5 
 6 def music(sec):
 7     print("Listening music")
 8     global a
 9     a = 1000
10     sleep(sec)
11 
12 t = threading.Thread(name = "my thread",\
13     target = music,args = (2,))
14 
15 t.start()
16 print("创建线程")
17 sleep(3)
18 print(a)
View Code

 

deamon属性:

     1,设置该属性默认为False, 主线程执行完毕后不会影响其他线程的执行;

     2, 如果设置为True, 则主线程执行完毕其他线程也终止执行;

代码:

设置daemon:               t.setDaemon(True)   或  t.daemon = True

获取daemon属性值:   t.isDaemon()

import threading
from time import sleep,ctime 

def fun():
    print("This is a thread test")
    sleep(5)
    print("thread over")

t = threading.Thread(name = 'levi',\
    target = fun)

# t.setDaemon(True)
t.daemon = True 
print(t.isDaemon())

t.start()

print(t.is_alive())  #线程状态
print(t.name) #线程名称

t.join(2)

print("all over",ctime())
View Code

 

线程间的通信:

全局变量进行通信;

线程间的同步和互斥;

import threading 
from time import sleep 

s = None 

e = threading.Event()

def bar():
    print("呼叫foo")
    global s 
    s = "天王盖地虎"

def foo():
    print('foo等口令')
    sleep(2)
    print('foo收到 %s'%s)
    e.set()

def fun():
    sleep(1)
    e.wait()
    print("内奸出现")
    global s 
    s = "小鸡炖蘑菇"   

t1 = threading.Thread\
(name = 'bar',target = bar)

t2 = threading.Thread\
(name = 'foo',target = foo)

t3 = threading.Thread\
(name = 'fun',target = fun)

t1.start()
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()
View Code

 

线程 event:

创建事件对象:   e = threading.Event()

e.wait([timeout])  如果e被设置则不会阻塞,未被设置则阻塞 ;timeout为阻塞的超时时间;

e.set() 将e变为设置是状态

e.clear() 将e变为未设置状态;

from threading import * 
import random 
from time import sleep 

a = 500

#创建事件对象
e = Event()

#子线程不断减少a 但是希望a的值不会少于100
def fun():
    global a
    while True:
        sleep(2)
        print('a = ',a)
        e.wait()
        a -= random.randint(0,100)

t = Thread(target = fun)
t.start()

#主线程不断的让a增加以确保a不会小于100
while True:
    sleep(1)
    a += random.randint(1,10)
    if a > 100:
        e.set()
    else:
        e.clear()

t.join()
View Code

 

线程锁:

lock = threading.Lock()   创建线程锁;

lock.acquire()    上锁

lock.release()    解锁

import threading 

a = b = 0 

lock = threading.Lock()

def value():
    while True:
        lock.acquire()
        if a != b:
            print("a = %d,b = %d"%(a,b))
        lock.release()

t = threading.Thread(target = value)
t.start()

while True:
    lock.acquire()
    a += 1
    b += 1
    lock.release()
t.join()
View Code

 

创建自己的线程类:

1,自定义类 继承于 原有线程类Thread

2, 复写原有的run方法;

3,创建线程对象调用start的时候会自动执行run

from time import ctime,sleep 
import threading
 

#编写自己的线程类 
class MyThread(threading.Thread):
    def __init__(self,func,args,name = 'Levi'):
        threading.Thread.__init__(self)
        self.func = func 
        self.name = name 
        self.args = args 

    #自定义 线程启动函数 
    def run(self):
        self.func(*self.args)

#待启动的线程函数
def player(file,time):
    for i in range(2):
        print('start playing %s:%s'\
            %(file,ctime()))
        sleep(time)

t = MyThread(player,('baby.mp3',3))

t.start()

t.join()
View Code

 线程池第三方模块  :threadpool

sudo pip3 install  threadpool

 

GIL (全局解释器锁)

python  --->   支持多线程  ----> 同步和互斥 ---> 加锁 --->超级锁 ---> 解释器在同一时刻只能解释一个线程;

大量python库为了省事依赖于这种机制----> python多线程效率低;

GIL 即为从python解释器由于 上锁带了的同一时刻只能解释一个线程的问题;

解决方案:

1, 不使用线程,转而使用进程;

2, 不使用c 作为解释器 java  c# 都可以做python解释器;

(1)IO密集型: 程序中进行了大量的IO操作,只有少量的CPU操作;

在内存中进行了数据的交换的操作都可以认为是IO操作;

特点: 速度较慢,使用cpu不高;

(2)cpu密集型(计算密集型):大量的程序都在进行运算操作;

特点:cpu占有率高

效率测试:

Line cpu 1.224205732345581
Line IO 4.142379522323608

Thread cpu 0.7009162902832031
Thread IO 3.458016872406006

Process cpu 0.6419346332550049
Process IO 1.8482108116149902

总结:多线程的工作效率和单线程几乎相近,而多进程要比前两者有明显的效率提升

设计模式:

设计模式代表了一种最佳实践,是被开发人员长期开发总结,用来解决某一类问题的思路方法。这种方法保证了代码的效率,也易于理解;

单例模式,工厂模式,生产者模式。。。

生产者消费者模式:

高内聚: 在同一模块内,实现单一功能,尽量不使功能混杂;

低耦合: 不同的模块之间尽量相互独立,减少模块间的影响;

代码实现

from threading import Thread 
#python标准库中的队列模块
import queue 
import time  

#创建一个队列模型作为商品的仓库
q = queue.Queue()

class Producer(Thread):
    def run(self):
        count = 0
        while True:
            if q.qsize() < 50:
                for i in range(3):
                    count += 1
                    msg = "产品 %d"%count
                    q.put(msg)  #将产品放入队列
            time.sleep(1)

class Customer(Thread):
    def run(self):
        while True:
            if q.qsize() > 20:
                for i in range(2):
                    msg = q.get() #从仓库拿到商品
                    print("消费了一个 %s"%msg)
            time.sleep(1)

#创建三个生产者
for i in range(3):
    p = Producer()
    p.start()

#创建5个消费者
for i in range(5):
    p = Customer()
    p.start()
View Code

 

总结:

1,进程和线程的区别

2.会创建使用线程 threading
3.掌握基本的线程间同步互斥编程方法
4.知道什么是GIL
5.了解设计模式的概念
*************************************************************

面试问题:

1. 进程和线程的区别
2. 什么是同步和互斥
3. 给一个具体的情况,问采用进程还是线程为什么
4. 你是怎么处理僵尸进程的
5. 怎么测试一个硬盘的读写速度
6. xxx框架 是用的多进程还是多线程并发
7. 进程间通信方式知道哪些,都有什么特点

 同步

互斥

 

posted on 2018-06-18 20:24  微子天明  阅读(189)  评论(0编辑  收藏  举报

导航