同步和异步,进程,线程和协程之间的区别和联系

同步和异步、阻塞和非阻塞

  • 异步: 多任务, 多个任务之间执行没有先后顺序,可以同时运行,执行的先后顺序不会有什么影响,存在的多条运行主线
  • 同步: 多任务, 多个任务之间执行的时候要求有先后顺序,必须一个先执行完成之后,另一个才能继续执行, 只有一个主线
  • 阻塞:从调用者的角度出发,如果在调用的时候,被卡住,不能再继续向下运行,需要等待,就说是阻塞
  • 非阻塞: 从调用者的角度出发, 如果在调用的时候,没有被卡住,能够继续向下运行,无需等待,就说是非阻塞

1)同步、异步

函数或方法被调用的时候,调用者是否得到最终的结果。

  • 直接得到最终结果的结果,就是同步调用。(打饭模型,打饭不打好不走开,直到打饭给我后才离开)
  • 不直接得到的最终的结果,就是异步调用。(打饭,不会一直等着,会时不时的过来看看,打完了把饭拿走,异步不保证多长时间打完了饭)

2)阻塞、非阻塞:

函数或方法调用的时候,是否立即返回。

  • 立即返回就是非阻塞调用。
  • 不立即返回就是阻塞调用。

3)区别:

  • 同步、异步,与阻塞、非阻塞不相关。
  • 同步、异步强调的是结果。阻塞和非阻塞强调的是时间,是否等待。
  • 同步与异步区别在于:调用者是否得到了想要的最终结果。
  • 同步就是一直要执行到返回最终结果。异步就是直接返回了,但是返回的不是最终的结果,调用者不能通过这种调用得到结果,还要通过被调用者,使用其他方式通知调用者,来取回最终结果。
  • 阻塞与非阻塞的区别在于,调用者是否还能干其他的事情。
  • 阻塞,调用者只能干等。非阻塞,调用者可以先忙一会别的,不用一直等。

4)联系:

  • 同步阻塞:调用者阻塞,直到等到拿到最终结果。(打饭模型,什么事情也不敢,就等着打饭,打饭是结果,什么也不干,一直在等着,同步加阻塞)
  • 同步非阻塞:(等着打饭,但是可以玩会手机,看看电视,打饭是结果,但是不用一直在等着)
  • 异步阻塞:(我要打饭,你说等着较好,并没有返回饭给我,我啥事不干,就干等着饭好了叫我)
  • 异步非阻塞:回调的话。(我要打饭,你说等较好,并没有返回饭给我,可以在旁边看看电视,玩玩手机,饭好了叫我)

进程、线程和协程之间的区别和联系

定义

  • 进程: 一个运行起来的程序或者软件叫做进程,进程是操作系统分配资源的 基本单位
  • 线程:指进程内的一个执行单元,也是进程内的可调度实体。
  • 协程:是一种程序组件,是由子例程(过程、函数、例程、方法、子程序)的概念泛化而来的,子例程只有一个入口点且只返回一次,而协程允许多个入口点,可以在指定位置挂起和恢复执行。

区别

  1. 进程是资源分配的最小单位,线程是CPU调度的最小单位.
  2. 进程是操作系统资源分配的单位
  3. 线程是CPU调度的单位
  4. 进程切换需要的资源最大,效率很低
  5. 线程切换需要的资源一般,效率一般
  6. 协程切换需要资源很小,效率高

线程与进程的区别

  1. 同一个进程中的线程共享同一内存空间,但是进程之间是独立的。
  2. 同一个进程中的所有线程的数据是共享的(进程通讯),进程之间的数据是独立的。
  3. 对主线程的修改可能会影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。
  4. 一个进程至少有一个线程
  5. 同一个进程的线程之间可以直接通信,但是进程之间的交流需要借助中间代理(队列)来实现
  6. 创建新的线程很容易,但是创建新的进程需要对父进程做一次复制。
  7. 一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。
  8. 线程启动速度快,进程启动速度慢(但是两者运行速度没有可比性)。

协程与线程的比较

  1. 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
  2. 线程进程都是同步机制,而协程则是异步
  3. 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

函数

# 线程
from threading import Thread
# 线程间队列
import queue

# 进程、进程间队列
from multiprocessing import Process, Queue

#时间模块
import time

#注:线程队列与进程队列不通用,可以通过 as 创建 昵称
#进程间队列:from multiprocessing import  Queue as  PQueue
#线程间队列:from queue  import Queue  as  QQueue

# 进程一的线程一
# 将数据放入线程间的队列
def process1_thread1(q1):
    l = [1, 2, 3]
    for i in l:
        q1.put(i)
        print("进程一的线程一放第{}数据....".format(i))


# 进程一的线程二
# 从线程中取出放入进程间的队列
def process1_thread2(q1, q2):
    while True:
        try:
            data = q1.get(timeout=2)
            print("进程一的线程二取数据:",data)
            q2.put(data)
            print("进程一的线程二放数据....")

        except:
            break


# 进程二的线程一
# 放入线程间的队列
def process2_thread1(q2, q3):
    while True:
        try:
            data = q2.get(timeout=2)
            print("进程二的线程一取数据:",data)
            q3.put(data)
            print("进程二的线程一放数据....")
        except:
            break


# 进程二的线程二
# 从线程间的队列取出并输出
def process2_thread2(q3):
    while True:
        try:
            data = q3.get(timeout=2)
            print("进程二的线程二取数据....",data)
        except:
            break


def process1(q2):
    # 创建线程间的队列
    q1 = queue.Queue()
    # 创建进程一的两个线程
    p1t1 = Thread(target=process1_thread1, args=(q1,))
    p1t2 = Thread(target=process1_thread2, args=(q1, q2))
    # 启动两个线程
    p1t1.start()
    p1t2.start()
    # 阻塞,防止死机
    p1t1.join()
    p1t2.join()


def process2(q2):
    # 创建线程间通信
    q3 = queue.Queue()
    # 创建进程二的两个线程
    p2t1 = Thread(target=process2_thread1, args=(q2, q3))
    p2t2 = Thread(target=process2_thread2, args=(q3,))
    # 启动两个线程
    p2t1.start()
    p2t2.start()
    # 阻塞,防止死机
    p2t1.join()
    p2t2.join()


if __name__ == '__main__':
    # 创建进程间队列
    q2 = Queue()
    #创建进程一
    p1 = Process(target=process1, args=(q2,))
    #启动进程一
    p1.start()
    #创建进程二
    p2 = Process(target=process2, args=(q2,))
    #启动进程二
    p2.start()

函数

from threading import Thread
import requests
import time
import UserAgent
from queue import Queue
base_url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1562211235205&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=python&pageIndex={}&pageSize=10&language=zh-cn&area=cn'
headers = UserAgent.getUserAgentC()


def getUrl_and_putData(q,q2):
    while True:
        try:
            url = q.get(timeout = 2)
            response = requests.get(url,headers = headers).json()
            data = response["Data"]["Posts"][0]["RecruitPostName"]
            q2.put(data)
        except:
            break
def getData(q2):
    while True:
        try:
            data = q2.get(timeout = 2)
            print(data)
            time.sleep(1)
        except:
            if flag:
                print("没有数据了,退出...")
                break
            else:
                print("队列中还没数据,等待ing...")
if __name__ == '__main__':
    flag  = False
    q = Queue()
    q2 = Queue()

    for i in range(75):
        url = base_url.format(i)
        q.put(url)

    for i in range(1,4):
        t = Thread(target=getUrl_and_putData,args=(q,q2))
        t.start()
    t.join()

    for i in range(1,4):
        t = Thread(target=getData,args=(q2,))
        t.start()
    flag = True

#导入程序所用到的资源
from threading import Thread
from queue import Queue
import requests
#随机获取请求头
from fake_useragent import UserAgent

#定义起始URL
base_url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1562211235205&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=python&pageIndex={}&pageSize=10&language=zh-cn&area=cn'
headers = {"User-Agent": UserAgent().random}

#生产者
class Produce(Thread):
    def __init__(self,name,url_q,data_q):
        #继承父类初始化方法
        super().__init__()
        self.name =name
        self.url_q = url_q
        self.data_q = data_q
    #重写run方法
    def run(self):
        while True:
            try:
                #从url队列中取出url
                url = self.url_q.get(timeout=1)
                print(self.name,url)
                #获取页面资源并将其转换为json格式
                response = requests.get(url,headers = headers).json()
                #将数据放入data队列
                self.data_q.put(response)
            except:
                break
#消费者
class Consumer(Thread):
    def __init__(self,name,data_q):
        #继承父类初始化方法
        super().__init__()
        self.name = name
        self.data_q = data_q
    #重写run方法
    def run(self):
        while True:
            try:
                #将数据从data队列中取出
                data = self.data_q.get(timeout=1)
                #输出json中所需要的数据
                print(self.name,data["Data"]["Posts"][0]["RecruitPostName"])
            except:
                # 如果flag为true时退出循环
                if flag:
                    break

#主函数
if __name__ == '__main__':
    #创建队列
    url_q = Queue()
    data_q = Queue()
    #定义一个退出标志
    flag = False
    #将拼接url
    for i in range(1,75):
        url = base_url.format(i)
        #将url放入url队列中
        url_q.put(url)
    #定义消费者名称列表
    C_list = ["萧炎","林动","牧尘"]
    #定义生产者名称列表
    P_list = ["阿猫","阿狗","阿猪"]
    #定义线程列表
    P_thread_list = []
    #创建生产者线程
    for p_name in P_list:
        p = Produce(p_name,url_q,data_q)
        p.start()
    #创建消费者进程
    for c_name in C_list:
        c = Consumer(c_name,data_q)
        c.start()
    #主线程任务结束之后,进入阻塞状态,
    # 一直等待其他的子线程执行结束之后,主线程在终止
    for p_t in P_thread_list:
        p_t.join()
    #阻止主线程终止,子线程结束后,将flag标志置为True,线程中的循环方可退出
    flag = True

你可能感兴趣的:(网络编程)