并发编程 --- 进程,线程

目录

  • 进程
  • 线程

进程

1.进程互斥锁

异步可以让多个任务在几个进程中并发处理,他们之间没有运行顺序,一旦开启也不受我们的控制,尽管并发编程让我们更加充分的利用IO资源,但是当多个进程使用同一份资源的时候,就会引发数据安全或顺序混乱的问题

import json
import time
from multiprocessing import Process
from multiprocessing import Lock

# 查看余票
def search(user):
    # 打开data文件查看余票
    with open('data.txt', 'r', encoding='utf-8') as f:
        dic = json.load(f)
    print(f'用户{user}查看余票,还剩{dic.get("ticket_num")}...')

# 开始抢票
def buy(user):
    # 先打开获取车票数据
    with open('data.txt', 'r', encoding='utf-8') as f:
        dic = json.load(f)

    # 模拟网络延时
    time.sleep(1)

    # 若有票,修改data数据
    if dic.get("ticket_num") > 0:
        dic['ticket_num'] -= 1
        with open('data.txt', 'w', encoding='utf-8') as f:
            json.dump(dic, f)
        print(f'用户: {user}抢票成功!')

    else:
        print(f'用户: {user}抢票失败!')

# 开始抢票
def run(user, mutex):
    # 并发: 异步执行
    search(user)

    # 串行: 同步执行
    mutex.acquire()
    buy(user)
    mutex.release()

if __name__ == '__main__':
    # 调用Lock()类得到一个锁对象
    mutex = Lock()

    # 同时来10个用户抢票
    for i in range(10):
        # 并发开启10个子进程
        p = Process(target=run, args=(f'用户{i}', mutex))
        p.start()

2.队列

1.队列的概念

创建一个共享的进程队列,可以使用Queue实现对进程之间的数据传递。

2.队列的使用方法
from multiprocessing import Queue

# 调用队列类,实例化队列对象
q = Queue(5)   # 5指的是队列中可以存放五个参数,如果不穿参,可以放无限个参数,前提是硬件能跟得上

# 添加队列
q.put(1)   # 变量1传入队列中,如果队列已经添加满了,就会卡住

# 判断队列是否位空
print(q.empty())  # 返回位True为空,False不为空

# 取出队列
print(q.get())    # 获取数据遵循‘先进先出’,若队列中无数据可取,也会卡住

# 取数据时不卡住
print(q.get_nowait())  # 没有数据的时候会报错。

# 查看队列是否满了
print(q.full())   # 满了为True,没有满位False

3.进程之间的通信

进程之间的数据是相互隔离的,要想实现进程间的通信(IPC),可以使用multiprocessing模块中的队列和管道,这两种方法是可以实现进程间数据传输的,由于队列是管道+锁的方式实现的,所以我们着重研究队列。

from multiprocessing import Process,Queue

def producer(q):
    q.put('hello big baby')

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

if __name__ == '__main__':
    q = Queue()
    p = Process(target=producer,args=(q,))
    p1 = Process(target=consumer,args=(q,))

    p.start()
    p1.start()

 # 输出为 hello big baby

4.生产者与消费者

生产者:生产数据的

消费者:消费数据的

线程

1.什么是线程

线程与进程都是虚拟单位,目的是为了更好的描述某种事物

进程:资源单位

线程:执行单位

开启一个进程,一定会有一个线程,线程才是真正的执行者,

2.为什么要使用线程

为了节省内存资源

开启进程会发生的两件事情:

1.开辟一个名称空间,每开启一个进程空间,都会占用一份内存资源,

2.会自带一个线程,

开启线程:

1.一个进程可以开启多个线程,

2.线程的开销远小于进程

注意:线程不能实现并行,线程只能实现并发,进程可以实现并行。

3.线程两种创建方式

进程不能直接在import下直接调用,线程可以。

# 开启线程方式1:
from threading import Thread
import time
def task():
    print('线程开启')
    time.sleep(1)
    print('线程结束')

if __name__ == '__main__':
    t = Thread()
    t = Thread(target=task)
    t.start()
    print('主')

# 开启线程方式2:
from threading import Thread
import time

class Sayhi(Thread):
    def __init__(self,name):
        super().__init__()
        self.name = name
    def run(self):
        time.sleep(2)
        print(self.name)

if __name__ == '__main__':
    t = Sayhi('wang')
    t.start()
    print('主')

内存就像一个工厂,子进程就像一个工厂车间,线程就像车间内的流水线

4.线程对象的属性

线程之间的数据是共享的

5.守护线程

无论是进程还是线程,都遵循:守护xxx会等待主xxx运行结束完毕之后被销毁,需要强调的是运行完毕并非终止运行

from threading import Thread
import time

def say(name):
    time.sleep(1)
    print(name)

if __name__ == '__main__':
    t = Thread(target=say,args=('wang',))
    t.setDaemon(True)
    t.start()

    print('主进程')
    print(t.is_alive())

6.线程互斥锁

from threading import Thread, Lock
import time

mutex = Lock()

n = 100

def task(i):
    print(f'线程{i}启动...')
    global n
    # mutex.acquire()
    temp = n
    time.sleep(0.1)  # 一共等待10秒
    n = temp-1
    print(n)
    # mutex.release()

if __name__ == '__main__':
    t_l=[]
    for i in range(100):
        t = Thread(target=task, args=(i, ))
        t_l.append(t)
        t.start()

    for t in t_l:
        t.join()

    # 100个线程都是在100-1
    print(n)

原文地址:https://www.cnblogs.com/whkzm/p/11722083.html

时间: 2024-10-29 12:42:14

并发编程 --- 进程,线程的相关文章

Python并发编程-进程 线程 协程

一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据集:数据集则是程序在执行过程中所需要使用的资源 3.进程控制块:进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感 知进程存在的唯一标志. 二.线程                                                                        

Java并发编程:线程的同步

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

第十五章、并发编程之线程

目录 第十五章.并发编程之线程 1.什么是线程 2. 进程和线程的区别 3. 开启线程的两种方式 函数开启 类开启 4.子线程与子进程创建速度 5.子线程共享数据的证明 6.线程的join方法 单个子线程 多个子线程 思考 7.了解进程的join 8. 线程的其他相关用法 第十五章.并发编程之线程 1.什么是线程 纠正概念:进程其实不是个执行单位,进程是一个资源单位,每个进程内自带一个线程,线程才是cpu上的执行单位 抽象理解: 进程是指在系统中正在运行的一个应用程序:线程是系统分配处理器时间资

Java并发编程:线程的创建

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

【转】Java并发编程:线程池的使用

Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPool

68:Scala并发编程原生线程Actor、Cass Class下的消息传递和偏函数实战解析及其在Spark中的应用源码解析

今天给大家带来的是王家林老师的scala编程讲座的第68讲:Scala并发编程原生线程Actor.Cass Class下的消息传递和偏函数实战解析 昨天讲了Actor的匿名Actor及消息传递,那么我们今天来看一下原生线程Actor及CassClass下的消息传递,让我们从代码出发: case class Person(name:String,age:Int)//定义cass Class class HelloActor extends Actor{//预定义一个Actor  def act()

19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权.因为生产者如果不释放对临界资源的占用权,那么消费者就无法消费队列中的商品,就不会让队列有空间,那么生产者就会一直无限等待下去.因此,一般情况下,当队列满时,会让生产者交出对

Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)

Java并发编程系列[未完]: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程:线程间的协作(wait/notify/sleep/yield/join) 一.线程的状态 Java中线程中状态可分为五种:New(新建状态),Runnable(就绪状态),Running(运行状态),Blocked(阻塞状态),Dead(死亡状态). New:新建状态,当线程创建完成时为新

Java并发编程:线程池的使用(转)

Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPool

JAVA并发编程3_线程同步之synchronized关键字

在上一篇博客里讲解了JAVA的线程的内存模型,见:JAVA并发编程2_线程安全&内存模型,接着上一篇提到的问题解决多线程共享资源的情况下的线程安全问题. 不安全线程分析 public class Test implements Runnable { private int i = 0; private int getNext() { return i++; } @Override public void run() { // synchronized while (true) { synchro