Python3.x基础学习-线程和进程(二)

进程、线程、协程对比

进程是操作系统资源分配的单位
线程是CPU调度的单位
进程切换需要的资源最大,效率很低
线程切换需要的资源一般,效率一般(当然在不考虑GIL的情况下)
协程切换任务资源小,效率高
多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中,所以是并发

同步和异步

异步:调用在发出之后,这个调用就直接返回,不管有无结果:异步是过程
非阻塞:关注的是程序在等待调用结果(消息,返回值)时的状态,指在不能立刻得到结果之前,该调用不会阻塞当前线程

同步异步的区别
同步:一个服务的完成需要依赖其他服务时,只有等待被依赖的服务完成后,才算完成,这是一种可靠的服务序列。要么成功都成功,要么失败都失败,
服务的状态可以保持一致
异步:一个服务的完成需要依赖其他服务时,只通知其他依赖服务开始执行,而不需要等待被依赖的服务完成,此时该服务就算完成了。被依赖的服务是
否最终完成无法确定,因此他是一个不可靠的服务序列

消息通知中的同步和异步:
同步:当一个同步调用发出后,调用者一直等待返回消息(或者调用结果)通知后,才能进行后续的执行
异步:当一个异步过程调用发出后,调用者不能立刻得到返回消息(结果)。在调用结束之后,通过消息回调来通知调用者是否调用成功。

阻塞和非阻塞区别:
阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务,函数只有在得到结果之后,才会返回
非阻塞:非阻塞和阻塞的结果相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回

同步与异步是对应的,他们是线程之间的关系,两个线程之间要么是同步的,要么是异步的

阻塞与非阻塞是同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。

阻塞是使用同步机制的结果,非阻塞则是使用异步机制的结果

守护线程

setDaemon() 将当前线程设置成守护线程来守护主线程:-当主线程结束后,守护线程也就结束,不管是否执行完成
-应用场景:qq多个聊天窗口,就是守护线程
注意:需要在子线程开启的时候设置成守护线程,否则无效

import time,threading

def dance():
    for i in range(3):
        time.sleep(0.5)
        print("正在跳舞")
def sing():
    for i in range(3):
        time.sleep(0.8)
        print('正在唱歌')

t1 = threading.Thread(target=dance)
t2 = threading.Thread(target=sing)

t1.setDaemon(True)
t2.setDaemon(True)
t1.start()
t2.start()
time.sleep(1)
print("时间结束。ending")

# 正在跳舞
# 正在唱歌
# 时间结束。ending
# ------run------- 0
# ------run------- 1
# ------run------- 2
# 正在跳舞

-getName() 获取线程的名称
-setName() 设置线程的名称
-isAlive() 判断当前线程存活状态

import time,threading

def dance():
    for i in range(3):
        time.sleep(0.8)
        print('正在跳舞')

def sing():
    for i in range(3):
        time.sleep(0.8)
        print("正在唱歌")

t1 = threading.Thread(target=dance)
t2 = threading.Thread(target=sing)
t1.setName('线程1')
# t2.setName('线程2')
print(t1.is_alive())
t1.start()
print(t1.is_alive())
t2.start()
print(t1.getName())
print(t2.getName())

# False
# True
# 线程1
# Thread-2
# ------run------- 0
# ------run------- 1
# ------run------- 2
# 正在跳舞
# 正在唱歌
# 正在唱歌
# 正在跳舞
# 正在唱歌
# 正在跳舞

threading.currentThread():返回当前的线程变量
threading.enumrate(): 返回一个包含正在运行的线程list,正在运行线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount():返回正在运行的线程数量,与len(threading.enumrate())有相同的结果
import threading,time

def dance():
    print('dance',threading.current_thread())
    for i in range(3):
        time.sleep(0.5)
        print('正在跳舞')
def sing():
    print('sing',threading.current_thread())
    for i in range(3):
        time.sleep(0.5)
        print('正在唱歌')

t1 = threading.Thread(target=dance)
t2 = threading.Thread(target=sing)

print(threading.current_thread())
# print(threading.enumerate())
t1.start()
t2.start()

print('启动后的线程列表-->',threading.enumerate())
print(threading.active_count())
print(len(threading.enumerate()))

# <_MainThread(MainThread, started 1536)>
# dance <Thread(Thread-1, started 2000)>
# sing <Thread(Thread-2, started 10484)>
# 启动后的线程列表--> [<_MainThread(MainThread, started 1536)>, <Thread(Thread-1, started 2000)>, <Thread(Thread-2, started 10484)>]
# 3
# 3
# 正在唱歌
# 正在跳舞
# 正在唱歌
# 正在跳舞
# 正在唱歌
# 正在跳舞
from threading import Thread

class MyThread(Thread):
    def __init__(self,num):
        super(MyThread,self).__init__()
        self.num =num
    def run(self):
        for i in range(self.num):
            print('------run-------',i)

if __name__ == '__main__':
    my = MyThread(3)
    my.start()
    
# ------run------- 0
# ------run------- 1
# ------run------- 2
多线程开发的时候共享全局变量会带来资源竞争
# 多线程开发的时候共享全局变量会带来资源竞争的效果,也就是数据不安全

import threading,time
g_num = 0

def func1(n):
    global g_num
    for i in range(n):
        time.sleep(0.01)
        g_num+=1
    print('--func1---',g_num)

def func2(n):
    global g_num
    for i in range(n):
        time.sleep(0.01)
        g_num+=1
    print('--func2--',g_num)

if __name__ == '__main__':
    t1 = threading.Thread(target=func1,args=(10000,))
    t2 = threading.Thread(target=func2,args=(10000,))
    t1.start()
线程锁

from threading import Thread,Lock

# 互斥锁
lock = Lock()  # 创建锁
lock.acquire() # 加锁
lock.release() # 释放锁

g_num = 0

def func1(n):
    global g_num
    for i in range(n):
        lock.acquire()
        g_num+=1
        lock.release()
    print('--in func1--',g_num)
def func2(n):
    global g_num
    for i in range(n):
        lock.acquire()
        g_num+=1
        lock.release()
    print('--in func2--',g_num)

if __name__ =='__main__':
    lock = Lock()
    t1 = Thread(target=func1,args=(10000,))
    t2 = Thread(target=func2,args=(10000,))
    t1.start()
    t2.start()

# --in func1-- 10000
# --in func2-- 20000


# 在多个线程共享资源的时候,如果两个线程分别占有一部分资源,并且同时等待对方的资源,就会造成死锁现象
# 如果锁之间相互嵌套,就有可能出现死锁。因此尽量不要出现锁之间的嵌套

import threading,time
printer_lock = threading.Lock() # 创建打印机锁
paper_lock =threading.Lock()   #简历锁

class Printer(threading.Thread):
    def run(self):
        print('--printer start--')
        paper_lock.acquire()
        time.sleep(1)
        print("编写简历1")
        printer_lock.acquire()
        print("正在使用打印机1")
        printer_lock.release()
        paper_lock.release()
        print("printer end")

class Paper(threading.Thread):
    def run(self):
        print("---paper start--")
        printer_lock.acquire()
        time.sleep(1)
        print('编写简历2')
        paper_lock.acquire()
        print("正在使用打印机2")
        printer_lock.release()
        paper_lock.release()
        print('paper end')

if __name__ == '__main__':
    printer = Printer()
    paper = Paper()
    printer.start()
    paper.start()
    
# --printer start--
# ---paper start--
# 编写简历2
# 编写简历1
# 一个threadLocal 变量虽然是全局变量,但是每个线程都只能读写自己线程的独立副本,互不干扰。
# threadLocal 解决了参数在一个线程中各个函数之间相互传递的问题

import threading
local = threading.local()

def func1():
    print(local.num)


def func2():
    local.num = 5
    local.num+=10
    print(threading.current_thread())
    func1()

t1 = threading.Thread(target=func2)
t1.start()

# <Thread(Thread-1, started 3284)>
# 15

线程和进程的对比

from multiprocessing import Process

import time

def func1():
    start = time.time()
    i = 0
    for i in range(20000000):
        i +=1

    end = time.time()
    print("func1--total_time:",end-start)


def func2():
    start = time.time()
    i = 0
    for i in range(20000000):
        i += 1

    end = time.time()
    print("func2--total_time:", end - start)

if __name__ == '__main__':
    p1 = Process(target=func1)
    p2 = Process(target=func2)
    p1.start()
    p2.start()

# func2--total_time: 1.0018956661224365
# func1--total_time: 1.0268356800079346

import threading
import time

def func1():
    start = time.time()
    i = 0
    for i in range(20000000):
        i +=1

    end = time.time()
    print("func1--total_time:",end-start)


def func2():
    start = time.time()
    i = 0
    for i in range(20000000):
        i += 1

    end = time.time()
    print("func2--total_time:", end - start)

if __name__ == '__main__':
    t1 = threading.Thread(target=func1)
    t2 = threading.Thread(target=func2)
    t1.start()
    t2.start()
    # func1 - -total_time: 1.7554385662078857
    # func2 - -total_time: 1.8083033561706543


import time
num =0
start =time.time()
for i in range(20000000):
    i+=1
end = time.time()

print(end-start)   #3.700019598007202

协程

# 协程切换一百万次

import time

def func1():
    start = time.time()
    for i in range(1000000):
        yield
    end = time.time()
    print("in func1 total_time:",end-start)

def func2(g):
    start = time.time()
    for i in range(1000000):
        g.__next__()
    end = time.time()
    print('in func2 total_time:',end-start)

g = func1()
func2(g)
# in func2 total_time: 0.11689877510070801

生产者模式和消费者模式

q = queue.Queue(3) 3表示只能存放3个数据
参数:maxsize 是队列中允许的最大项数。如果省略此参数,则无大小限制。返回值q是队列对象
2.put()方法,向队列中存放数据。如果队列已满,此方法阻塞直至有空间可用为止。
3.get()返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止
4.get_nowait():不等待,直到抛出异常
5.full()如果q已满,返回为True
6.q.empty()如果调用此方法时q为空,返回为True
7.qsize()获取队列中数据的个数
import queue

q = queue.Queue(2)
q.put("hello")
q.put("world")
print(q.full())
print(q.qsize())
print(q.get())
print(q.get())

# True
# 2
# hello
# world


import queue
import threading
import time
list = []
def produce(name):
for i in range(1,11):
print("%s生产了包子%d"%(name,i))
q.put(i)
time.sleep(0.5)

def custom(name):
while True:
print("%s吃了包子%d"%(name,q.get(timeout=10)))



if __name__ =='__main__':
q = queue.Queue()
t1 = threading.Thread(target=produce,args=('johnson',))
t2 = threading.Thread(target=custom,args=('may',))
t1.start()
t2.start()

# johnson生产了包子1
# may吃了包子1
# johnson生产了包子2
# may吃了包子2
# johnson生产了包子3
# may吃了包子3
# johnson生产了包子4
# may吃了包子4
# johnson生产了包子5
# may吃了包子5
# johnson生产了包子6
# may吃了包子6
# johnson生产了包子7
# may吃了包子7
# johnson生产了包子8
# may吃了包子8
# johnson生产了包子9
# may吃了包子9
# johnson生产了包子10
# may吃了包子10
 

练习

"""
创建两个进程:进程A和进程B,用jcq消息队列实现他们的通信。
1、进程A里创建两个线程:线程A1 、线程A2.
在进程A1里创建一个a列表 [1,2,3,4,5,6], 线程A1用消息队列将列表传递给线程A2,线程A2.
对列表进行筛选,删除掉奇数。然后用进程jcq消息队列发送给进程B
2、在进程B里创建两个线程:线程B1、线程B2
线程B2.接受进程A发过来的数据,并把这些数据,原封不动的用线程消息队列传递给线程B1
线程B1求出所有数的和并打印结果
"""
from multiprocessing import Process,Queue
from threading import Thread
import queue
def JcA(Q):
    qa = queue.Queue()
    a=[1, 2, 3, 4, 5, 6]
    xca1 = Thread(target=XcA1,args=(qa,a))
    xca2 = Thread(target=XcA2,args=(qa,Q))
    xca1.start()
    xca1.join()
    xca2.start()
    xca2.join()
def XcA1(qa,lst):
    for i in lst:
        qa.put(i)
def XcA2(qa,Q):
    for i in range(qa.qsize()):
        num = qa.get()
        if num%2==0:
            pass #放到进程消息队列中
            Q.put(num)
# 2、在进程B里创建两个线程:线程B1、线程B2
# 线程B2.接受进程A发过来的数据,并把这些数据,原封不动的用线程消息队列传递给线程B1
# 线程B1求出所有数的和并打印结果
def JcB(Q):
    qb = queue.Queue()
    xcb1 = Thread(target=XcB1, args=(qb,))
    xcb2 = Thread(target=XcB2, args=(Q,qb))
    xcb2.start()
    xcb2.join()
    xcb1.start()
    xcb1.join()
def XcB1(qb):
   # pass  #从线程消息队列中取数据,求出所有数的和并打印结果
    sum = 0
    for i in range(qb.qsize()):
        sum+=qb.get()
    print(sum)
def XcB2(Q,qb):
    # pass#从进程队列中取数据,用线程消息队列传递给B1
    for i in range(Q.qsize()):
        qb.put(Q.get())
if __name__ == '__main__':
    Q = Queue()
    pa = Process(target=JcA,args=(Q,))
    pb = Process(target=JcB,args=(Q,))
    pa.start()
    pa.join()
    pb.start()
原文地址:https://www.cnblogs.com/johnsonbug/p/12710036.html