网络并发编程04--线程

1. 僵尸进程和孤儿进程


from multiprocessing import Process
import time


def test(name):
    print('%s is running..' % name)
    time.sleep(2)
    print('%s is over..' % name)


if __name__ == '__main__':
    p = Process(target=test, args=('jack',))
    p.start()

    print('主')

# 僵尸进程
	进程代码运行结束之后,并没有直接结束而是需要等待回收子进程资源才能结束

# 孤儿进程
	即 主进程已经死亡(非正常),但是子进程还在运行
    是有害的

2. 守护进程

守护进程:即 守护着某个进程,一旦进程结束,那么也随之结束

3. 互斥锁

import json
from multiprocessing import Process, Lock
import time
import random


# 查票
def serch(name):
    with open(r'data.txt', 'r', encoding='utf8') as f:
        data_dict = json.load(f)
        ticket_num = data_dict.get('ticket_num')
        print('%s 余票:' %(name, ticket_num))

# 买票
def buy(name):
    # 先查票
    with open(r'data.txt', 'r', encoding='utf8') as f:
        data_dict = json.load(f)
        ticket_num = data_dict.get('ticket_num')
    # 模拟一个延迟
    time.sleep(random.random())
    
    # 判断是否有余票
    if ticket_num > 0:
        # 将余票 减1
        data_dict['ticket_num'] -= 1
        # 重新写入
        with open(r'data.txt', 'w', encoding='utf8') as f:
            json.dump(data_dict, f)
        print('%s购买成功' % name)
    else:
        print('没票了')

def run(name, lock):
    search(name)
    lock.acquire()  # 申请锁,抢锁
    buy(name)
    lock.release()  # 释放锁

if __name__ == '__main__':
    lock = Lock()
    for i in range(1, 11):
        p = Process(target=run, args=('用户%s' % (i, lock)))
        p.start()


"问题:"并发情况下,操作同一份数据,极其容易造成数据错乱

解决:将并发编程串行,虽然降低了效率,但是提升了数据的安全

#   锁,就可以实现将并发变成串行的效果
    行锁,表锁

# 使用锁的注意事项
# 在主进程中产生,交由子进程使用
    1. 一定要在需要的地方枷锁,千万不要随意加
    2. 不要轻易的使用锁(死锁现象)
    # 在以后的编程生涯中,几乎不会接触到自己操作锁的情况


4. 消息队列

队列:先进先出

from multiprocessing import Queue

q = Queue(5)  # 括号内可以填写最大等待数

# 存放数据
q.put(111)
q.put(222)
print(q.full())
q.put(333)
q.put(444)
q.put(555)
print(q.full())
# q.put(666)  超出范围原地等待,直到有空缺位置

# 提取数据
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())  # 没有数据之后原地等待,直到有数据为止
print(q.get_nowait())  # 没有数据,立刻报错

print('xxxx')

"""
full 和 get_nowait能否用于多进程情况下的精确使用
    不能!!!!
	
队列的使用就可以打破进程间默认无法通信的情况

队列如果是用来存放数据的,那么他就叫做消息队列

"""

5. IPC机制

from multiprocessing import Queue,Process

def producer(q):
    q.put('p放的数据')

def consumer(q):
    print(q.get())

if __name__ == '__main__':
    q = Queue()
    q.put('主进程放的数据')
    p = Process(target=consumer, args=(q,))
    p.start()
    p.join()
    print(q.get())
    print('主进程')


6. 生产者消费者模型

"""
生产者
	负责产生数据
消费者
	负责处理数据

# 该模型需要解决供需不平衡现象
# 确保消费者在没有事物消费之后,如何结束

# 爬虫领域用的更多一些

"""

7. 线程

理论


"什么是线程?"
    # 进程其实是一个资源单位,真正被cpu执行的其实是进程里面的线程
    进程类似于工厂,线程类似于工厂中的流水线
    所有的进程肯定最少有一个线程

7.1 开设线程的两种方式


"开设线程的第一种方式"
from threading import Thread
import time


def test(name):
    print('%s is running..' % name)
    time.sleep(3)
    print('%s is over..' % name)

t = Thread(target=test, args=('jack',))
t.start()
print('主')


"""
开设进程需要做哪些操作
    1. 重新申请一块内存空间
    2. 将所需的资源全部导入

开设线程需要做哪些操作
    1. 上述两个步骤都不需要,所以开设线程消耗的资源要远比开进程的小

"""

"开设线程的第二种方式"

class MyClass(Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print('%s is running...' % self.name)
        time.sleep(2)
        print('%s is over...' % self.name)

obj = MyClass('jack')
obj.start()
print('主线程')

7.2 线程对象的join方法


from threading import Thread
import time


def test(name):
    print('%s is running...' % name)
    time.sleep(2)
    print('%s is over...' % name)

t = Thread(target=test, args=('jack',))
t.start()
t.join()  # 主线程等待子线程运行结束之后再向下运行
print('主')


7.3 线程对象的其他方法


# 1. 线程之间os.getpid() >>> 相等
# 验证同一个进程内,可以开设多个线程

# 2. active_count
# 当前有几个正在活跃的线程数

# 3. current_thread
# 获取当前线程的名字


from threading import Thread,active_count,current_thread
import time
import os


def test(name):
    print(os.getpid())
    print(current_thread().name)
    print('%s is running...' % name)
    time.sleep(2)
    print('%s is over...' % name)

t = Thread(target=test, args=('jack',))
t.start()
print(os.getpid())
# t.join()  # 主线程等待子线程运行结束之后再向下运行
print(current_thread().name)
print(active_count())
print('主')

7.4 守护进程


"""
主线程的结束,意味着整个进程的结束
    所以主线程需要等待里面所有非守护线程的结束才能结束

"""

from threading import Thread,active_count,current_thread
import time
import os


def test(name):
    print(os.getpid())
    print(current_thread().name)
    print('%s is running...' % name)
    time.sleep(3)
    print('%s is over...' % name)


t = Thread(target=test, args=('jack',))
t.daemon = True
t.start()


7.5 同一进程下线程之间数据共享

from threading import Thread
import time


money = 100

def test():
    global money
    money = 999

t = Threading(target=test)
t.start()
t.join()
print(money)


7.5 线程互斥锁

from threading import Thread,Lock
import time

num = 100

def test(lock):
    global num
    # 先获取num的数值
    lock.acquire()
    tmp = num
    # 模拟延迟效果
    time.sleep(1)
    # 修改
    tmp -= 1
    num = tmp
    lock.release()


t_list = []
lock = Lock()
for i in range(100):
    t = Thread(target=test, args=(lock,))
    t.start()
    # t.join()
    t_list.append(t)


for i in t_list:
    t.join()

print(money)

posted @ 2022-01-14 16:37  Joshua_jiaxue  阅读(39)  评论(0编辑  收藏  举报