广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python全栈开发之并发编程
  • 892
分享到

Python全栈开发之并发编程

Python 2023-01-31 07:01:17 892人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

No.1 线程 什么是多任务 就是操作系统可以同时运行多个任务,就是可以一边用浏览器上网,同时又可以听歌,还能再撩个×××姐,这就是多任务,操作系统会轮流把系统调度到每个核心上去执行 并发和并行 并发是指任务数多余cpu核数,通过操作系统的

No.1 线程

什么是多任务

就是操作系统可以同时运行多个任务,就是可以一边用浏览器上网,同时又可以听歌,还能再撩个×××姐,这就是多任务,操作系统会轮流把系统调度到每个核心上去执行

并发和并行

并发是指任务数多余cpu核数,通过操作系统的各种任务调度算法,实现多个任务

并行是指任务数小于cpu核数,即任务同时执行

单线程

import time

def say_hello(i):
    print('hello ', i)

if __name__ == '__main__':
    for i in range(5):
        say_hello(i)

多线程

import threading
import time

def say_hello(i):
    print('hello ', i)

if __name__ == '__main__':
    for i in range(5):
        t = threading.Thread(target=say_hello,args=(i,))
        t.start() # 当调用start方法时,才会正真的执行线程

主线程会等待子线程

import threading
import time

def say_hello(name):
    for i in range(5):
        print('hello ', i, name)

if __name__ == '__main__':
    say_hello('主线程')
    t1 = threading.Thread(target=say_hello,args=('t1',))
    t2 = threading.Thread(target=say_hello,args=('t2',))
    t1.start()
    t2.start()
    print('end')
# hello  0 主线程
# hello  1 主线程
# hello  2 主线程
# hello  3 主线程
# hello  4 主线程
# hello  0 t1
# hello  1 t1
# hello  2 t1
# hello  3 t1
# hello  4 t1
# hello  0 t2
# hello  1 t2
# hello  2 t2
# hello  3 t2
# hello  4 t2
# end

查看线程数量

import threading
import time

def say_hello(i):
    print('hello ', i)

if __name__ == '__main__':
    say_hello('主线程')
    for i in range(5):
        t = threading.Thread(target=say_hello,args=(i,))
        t.start()
        while True:
            length = len(threading.enumerate())
            print('当前运行的线程数为:%d' % length)
            if length <= 1:
                break
# hello  主线程
# hello  0
# 当前运行的线程数为:2
# 当前运行的线程数为:1
# hello  1
# 当前运行的线程数为:1
# hello  2
# 当前运行的线程数为:1
# hello  3
# 当前运行的线程数为:1
# hello  4
# 当前运行的线程数为:1

封装线程

为了让每个线程的封装性更加完整,我们通常会创建一个线程类,让这个线程类继承自threading.Thread,然后重写run方法就可以了

import threading
import time
class MyThread(threading.Thread):

    def run(self):
        for i in range(5):
            time.sleep(1)
            print(self.name + str(i))

if __name__ == '__main__':
    t = MyThread()
    t.start()

python的threading.Thread类的run方法,用于定义线程的功能函数,可以在我们自己的类中覆盖该方法,当创建自己的线程类对象后,可以start方法,进行调度

线程的执行顺序

线程的执行顺序是不确定的,当执行到sleep语句时,线程将会被阻塞,然后线程进入就绪状态,等待cpu的调度,线程调度自动选择一个线程执行

No.2 多线程

多线程共享全局变量

import threading
import time

num = 100
def demo1():
    global num
    for i in range(3):
        num -= 1
        print('num = ',num)

def demo2():
    print('num = ', num)

if __name__ == '__main__':
    print('线程创建之前num = ',num)
    t1 = threading.Thread(target=demo1)
    t1.start()
    time.sleep(1)
    t2 = threading.Thread(target=demo2)
    t2.start()
# 线程创建之前num =  100
# num =  99
# num =  98
# num =  97
# num =  97

在一个进程内的所有线程共享全局变量,能很方便的在多个线程之间共享数据,但是这也带来一个麻烦,就是线程就全局变量的随机修改可能会导致多线程之间对于全局变量的的混乱,即线程非安全

import threading
import time

num = 100
def demo1():
    global num
    for i in range(1000000):
        # lock.acquire()
        num += 1
        # lock.release()

def demo2():
    global num

    for i in range(1000000):
        # lock.acquire()
        num += 1
        # lock.release()

if __name__ == '__main__':
    print('线程创建之前num = ',num)
    # lock = threading.Lock()
    t1 = threading.Thread(target=demo1)
    t1.start()
    t2 = threading.Thread(target=demo2)
    t2.start()
    while len(threading.enumerate()) != 1:
        time.sleep(1)
    print('线程执行完毕num = ',num)
# 线程创建之前num =  100
# 线程执行完毕num =  1559954
两个线程分别对线程自增了10次,结果却是122,如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确

同步

对于多线程非安全的问题,可以采用同步的方式来解决,每个线程对数据的修改时,都要先上,处理完成后再解锁,在上锁的过程中不允许任何线程打扰,这样就能保证线程安全性了,数据也不会不正确

互斥锁

当多个线程几乎同时修改某一个共享数据的时候,需要进程同步控制,线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁,互斥锁为资源引入一个状态,锁定/非锁定,某个线程要更改共享数据时,此时资源状态为锁定,其他线程不能更改,当该线程修改完毕,将资源设置为非锁定,互斥锁保证了每次只能由一个线程进入写入,从而保证了多线程情况下数据的正确性

# 创建锁
lock = threading.Lock()

# 锁定
lock.acquire()

# 释放
lock.release()

使用互斥锁对两个线程对同一个全局变量各加1亿次

import threading
import time

num = 100
def demo1():
    global num
    for i in range(100000000):
        lock.acquire()
        num += 1
        lock.release()

def demo2():
    global num

    for i in range(100000000):
        lock.acquire()
        num += 1
        lock.release()

if __name__ == '__main__':
    print('线程创建之前num = ',num)
    lock = threading.Lock()
    t1 = threading.Thread(target=demo1)
    t1.start()
    t2 = threading.Thread(target=demo2)
    t2.start()
    while len(threading.enumerate()) != 1:
        time.sleep(1)
    print('线程执行完毕num = ',num)
# 线程创建之前num =  100
# 线程执行完毕num =  200000100

上锁解锁过程

当一个线程调用所的acquire方法获得锁时,锁就进入locked状态,每次只能有一个线程的锁,如果此时有另外一个线程试图获得锁,那么此时这个锁就会进入阻塞状态,直到拥有锁的线程调用release解锁之后,锁进入unlocked状态,其他线程就可以获得锁了

锁的优缺点

确保了某段关键代码只能由一个线程完整执行,确保了数据的完整性,阻止了多线程并发,使得包含的锁的代码只能以单线程执行,效率就大大降低了,还可能发生死锁

死锁

在线程共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会形成死锁

import threading
import time

class MyThread1(threading.Thread):
    def run(self):
        # lockA上锁
        lockA.acquire()
        # 延时1秒,等待另外那个线程 把lockB上锁
        print(self.name+' A start')
        time.sleep(1)
        # 堵塞,因为这个lockB已经被另外的线程抢先上锁了
        lockB.acquire()
        print(self.name+' B end')
        lockB.release()
        # lockA解锁
        lockA.release()

class MyThread2(threading.Thread):
    def run(self):
        # lockB上锁
        lockB.acquire()
        # 延时1秒,等待另外那个线程 把lockA上锁
        print(self.name+' B start')
        time.sleep(1)
        # 堵塞,lockA已经被另外的线程抢先上锁了
        lockA.acquire()
        print(self.name+' A end')
        lockA.release()
        # lockB解锁
        lockB.release()

if __name__ == '__main__':
    lockA = threading.Lock()
    lockB = threading.Lock()
    t1 = MyThread1()
    t2 = MyThread2()
    t1.start()
    t2.start()
# Thread-1 A start
# Thread-2 B start

如何避免死锁

import threading
import time

class MyThread1(threading.Thread):
    def run(self):
        lockA.acquire()
        print(self.name, 'A', 'start')
        time.sleep(1)
        # 如果在规定时间内可以上锁就返回True,反之。。。
        result = lockB.acquire(timeout=1)
        if result:
            print(self.name, 'B', 'start')
            lockA.release()
            print(self.name, 'A', 'end')
            lockB.release()
            print(self.name, 'B', 'end')
        else:
            lockA.release()

class MyThread2(threading.Thread):
    def run(self):
        lockB.acquire()
        print(self.name, 'B', 'start')
        time.sleep(1)
        lockA.acquire()
        print(self.name, 'A', 'start')
        lockA.release()
        print(self.name, 'A', 'end')
        lockB.release()
        print(self.name, 'B', 'end')

if __name__ == '__main__':
    lockA = threading.Lock()
    lockB = threading.Lock()
    t1 = MyThread1()
    t2 = MyThread2()
    t1.start()
    t2.start()

GIL

Python语言和GIL没有半毛钱关系,仅仅是由于历史原因在Cpython虚拟机,难以移除GIL

GIL,全局解释器锁,每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码

线程释放GIL锁的情况: 在io操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL

Python使用多进程是可以利用多核的CPU资源的

多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁

No.3 进程

什么是进程?

一个程序在运行期间,代码和程序运行所需的资源称为进程

进程的状态

工作中,任务数往往大于cpu核心数,所以一定有一些任务在执行,另外一部分是处于等待状态
就绪态,运行的条件已经满足,等待cpu执行
执行态,cpu正在执行该任务
等待态,等待某些条件满足

创建进程

from multiprocessing import Process
import time

def run_proc():
    while True:
        print('子线程')
        time.sleep(1)

if __name__ == '__main__':
    p = Process(target=run_proc)
    p.start()
    while True:
        print('主线程')
        time.sleep(1)

pid

from multiprocessing import Process
import time
import os
def run_proc():
    # 获取当前进程的pid
    print('子进程 pid = ',os.getpid())

if __name__ == '__main__':
    print('父进程 pid = ',os.getpid())
    p = Process(target=run_proc)
    p.start()

Process语法结构

Process([group [, target [, name [, args [, kwargs]]]]])
target 如果传递了函数的引用,可以让子进程执行内部代码
args 给target指定的函数传递参数,元组方式
kwargs 给target指定的函数传递命名参数
name 给进程设定一个名字
group 指定进程组
常用方法
start() 启动子进程
is_alive() 判断进程是否还在运行
join([timeout]) 是否等待子进程执行结束
terminate() 不管任务是否执行完毕,直接结束

进程不能共享全局变量

from multiprocessing import Process
import time
NUM_LIST = [11,22,33]

def demo1(num_list):
    num_list.append(44)
    print(num_list)

def demo2(num_list):
    num_list.append(55)
    print(num_list)

if __name__ == '__main__':
    p1 = Process(target=demo1,args=(NUM_LIST,))
    p2 = Process(target=demo2,args=(NUM_LIST,))
    p1.start()
    p2.start()
    print(NUM_LIST)
# [11, 22, 33]
# [11, 22, 33, 44]
# [11, 22, 33, 55]

进程、线程对比

定义

进程,能够完成多任务,例如,在一台电脑上登录多个QQ客户端

线程,能够完成多任务,例如,在一台电脑上和多个妹子聊天

区别

一个程序至少有一个进程,一个进程至少有一个线程,线程的划分尺度小于进程,是的多线程的并发高于多进程,进程在执行过程中拥有独立的内存单元,而线程却是共享的,线程的运行开销小,但是不安全,进程和它相反,所以我们要根据不同的场景选择适合的

进程池

当需要创建的线程数量不多时,我们可以直接利用Process动态生成进程,但是当进程数量上百甚至上千时,我们再采用Process创建进程就可以猝死了,此时可以使用pool,初始化pool时,可以指定一个最大进程数,当有新的请求提交到pool时,如果线程池没有满,那么会创建一个新的线程来执行该请求,否则,等待其他进程结束

from multiprocessing import Pool
import time

def func(arg):
  print(arg)
  time.sleep(1)

if __name__ == '__main__':
  pool = Pool(5)
  for i in range(30):
      pool.apply_async(func=func,args=(i,))
  pool.close() # 所有任务执行完毕
  pool.join() # 等待pool中所有子进程执行完成,必须放在close语句之后

pool函数解析

apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表
close():关闭Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;

进程池中的queue

from multiprocessing import Pool,Manager
import time
import random

def write(q):
    for i in [11,22,33]:
        if not q.full():
            q.put(i)
            print('put %s to queue' %i)
            time.sleep(random.random())

def read(q):
    while True:
        if not q.empty():
            value = q.get()
            print('get %s to queue' %value)
            time.sleep(random.random())
        else:
            break

if __name__ == '__main__':
    q = Manager().Queue()
    pool = Pool()
    pool.apply_async(write,args=(q,))
    # time.sleep(1)
    pool.apply_async(read,args=(q,))
    pool.close()
    pool.join()

进程间通信

进程间有时也需要通信,可以使用multiprocessing模块的Queue实现

初始化Queue()对象时,若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限
Queue.qsize() 返回当前队列包含的消息数量
Queue.empty() 如果队列为空,返回True,反之False
Queue.full() 如果队列满了,返回True,反之False
Queue.get([block[, timeout]]) 获取队列中的一条消息,然后将其从列队中移除,block默认值为True,如果block使用默认值,且没有设置timeout,消息列队如果为空,此时程序将被阻塞,直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则出"Queue.Empty"异常,如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常
Queue.get_nowait() 相当Queue.get(False)
Queue.put(item,[block[, timeout]] 将item消息写入队列,block默认值为True,如果block使用默认值,且没有设置timeout,消息列队如果已经没有空间可写入,此时程序将被阻塞,直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出"Queue.Full"异常,如果block值为False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常
Queue.put_nowait(item) 相当Queue.put(item, False)

栗子

from multiprocessing import Process,Queue
import time
import random

def write(q):
    for i in [11,22,33]:
        if not q.full():
            q.put(i)
            print('put %s to queue' %i)
            time.sleep(random.random())

def read(q):
    while True:
        if not q.empty():
            value = q.get()
            print('get %s to queue' %value)
            time.sleep(random.random())
        else:
            break

if __name__ == '__main__':
    q = Queue()
    t1 = Process(target=write,args=(q,))
    t2 = Process(target=read,args=(q,))
    t1.start()
    t1.join()
    t2.start()
    t2.join()

No.4 迭代器

迭代是遍历序列的一种方式,它可以记住序列的遍历位置,迭代器从第一个元素开始访问,只能向前,不能后退

可迭代对象

可以通过for...in...这类语句迭代的对象称为可迭代对象

如何判断一个对象是否可以迭代

可以使用inistance(obj,Iterable)判断一个对象是不是iterable对象

可迭代对象的本质

可迭代对象进行迭代的时候,我们发现没迭代一次,都会返回对象的中的下一条数据,一直往后读取数据直到数据全部迭代完成,那么,这个负责记录数据迭代到的索引的机制叫做迭代器,可迭代对象通过iter方法向我们提供一个迭代器,我们在迭代对象的时候,实际上就是调用该方法获取了一个迭代器,然后根据迭代器来获取数据的,也就说,具有iter方法 的对象称为可迭代对象

from collections import Iterable

class MyInt(int):
    def __iter__(self):
        pass

if __name__ == '__main__':
    myint = MyInt()
    print(isinstance(myint, Iterable)) # True

iter函数与next函数

可迭代对象通过iter函数获取迭代器,我们可以对获取到的迭代器不停的使用next函数来获取下一条数据,当我们对迭代器使用iter函数就是调用了可迭代对象的iter函数,注意,当我们迭代玩最后一个数据时,再次调用next函数会抛出StopIterable异常

迭代器iterable

当我们对迭代器使用next方法的时候,实际上时调用的next函数(Python2是next函数),所以,想构建一个迭代器,就要实现它的nextiter函数,实现了这两个函数,就是迭代器

class MyIterator(object):
    """自定义的供上面可迭代对象使用的一个迭代器"""
    def __init__(self):
        self.items = []
        self.current = 0 # current用来记录当前访问到的位置
    def add(self,value):
        self.items.append(value)

    def __next__(self):
        if self.current < len(self.items):
            item = self.items[self.current]
            self.current += 1
            return item
        else:
            raise StopIteration

    def __iter__(self):
        return self

if __name__ == '__main__':
    mi = MyIterator()
    mi.add(1)
    mi.add(2)
    mi.add(3)
    mi.add(4)
    mi.add(5)
    for num in mi:
        print(num)

for...in...本质

本质就是先通过iter获取迭代器,在通过迭代器不断的调用next方法,当遇到异常退出

迭代器应用场景

每次返回的数据不是在一个已有的数据集合中读取,而是程序通过一定的规律计算生成的,也就是说不用将所有要迭代的数据一次存储下来提供后续读取,这样可以节省很大空间

class FibIterator(object):
    def __init__(self, n):
        self.n = n
        self.current = 0
        self.num1 = 0
        self.num2 = 1

    def __next__(self):
        if self.current < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1+self.num2
            self.current += 1
            return num
        else:
            raise StopIteration

    def __iter__(self):
        return self

if __name__ == '__main__':
    fib = FibIterator(10)
    for num in fib:
        print(num, end=" ")

No.5 生成器

生成器

一边循环一边计算的机制,称为生成器,生成器是一种特殊的迭代器

创建生成器

将列表生成式的定界符改成()

G = ( x*2 for x in range(5))
G
<generator object <genexpr> at 0x000001E86BC993B8>

创建生成式和生成器的区别仅在于定界符,L是一个列表,G是一个生成器,我们可以直接打印出列表的每个元素,而对于生成其,我们可以按照迭代器的使用方法来使用

使用yield

def fib(n):
    current = 0
    num1, num2 = 0, 1
    while current < n:
        num = num1
        num1, num2 = num2, num1+num2
        current += 1
        yield num

if __name__ == '__main__':
    f = fib(10)
    for i in f:
        print(i)

使用了yield关键字的函数就是生成器,yield的作用有两点,一是保存当前运行状态,暂停执行,挂起生成器,二是将yield后面的表达式的值作为返回值返回,可以使用next函数让生成器从断点处继续执行,唤醒生成器

使用send唤醒

我们除了可以使用next函数来唤醒生成器,还可以使用send函数,使用send还可以在唤醒的同时从间断点传入一个附加数据

def fib(n):
    current = 0
    num1, num2 = 0, 1
    while current < n:
        num = num1
        num1, num2 = num2, num1+num2
        current += 1
        yield num

if __name__ == '__main__':
    f = fib(10)
    print(next(f))
    print(f.send('...'))

No.7 协程

协程概念

协程是什么

协程是Python中另外一种实现多任务的方式,只不是比比线程更小的执行单元,协程自带CPU上下文,只要在合适的时机,我们可以把一个协程切换到另一个协程,这要在这个过程中保存或恢复CPU上下文那么程序还是可以运行的,说到这,小伙伴们是不是想到了上文介绍的yield

协程和线程差异

在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住

简单实现协程

import time

def work1():
    while True:
        print("----work1---")
        yield
        time.sleep(0.5)

def work2():
    while True:
        print("----work2---")
        yield
        time.sleep(0.5)

def main():
    w1 = work1()
    w2 = work2()
    while True:
        next(w1)
        next(w2)

if __name__ == "__main__":
    main()

greenlet

安装greenlet pip3 install greenlet

from greenlet import greenlet
import time

def demo1():
    while True:
        print('Demo1 is running')
        gl2.switch()
        time.sleep(1)

def demo2():
    while True:
        print('Demo2 is running')
        gl1.switch()
        time.sleep(1)

if __name__ == '__main__':
    gl1 = greenlet(demo1)
    gl2 = greenlet(demo2)
    gl1.switch() # 切换到gl1执行

gevent

交替运行

import gevent

def demo():
    for i in range(10):
        print(gevent.getcurrent(),i)

if __name__ == '__main__':
    g1 = gevent.spawn(demo,)
    g2 = gevent.spawn(demo,)
    g3 = gevent.spawn(demo,)
    g4 = gevent.spawn(demo,)
    g1.join()
    g2.join()
    g3.join()
    g4.join()

自动切换

import gevent

def demo():
    for i in range(10):
        print(gevent.getcurrent(),i)
        gevent.sleep(1)

if __name__ == '__main__':
    g1 = gevent.spawn(demo,)
    g2 = gevent.spawn(demo,)
    g3 = gevent.spawn(demo,)
    g4 = gevent.spawn(demo,)
    g1.join()
    g2.join()
    g3.join()
    g4.join()

No.7 线程、进程、协程区别

进程是资源分配的单位

线程是操作系统调度的单位

进程切换需要的资源很最大,效率很低

线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)

协程切换任务资源很小,效率高

多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中,所以是并发

--结束END--

本文标题: Python全栈开发之并发编程

本文链接: https://www.lsjlt.com/news/190785.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python全栈开发之并发编程
    No.1 线程 什么是多任务 就是操作系统可以同时运行多个任务,就是可以一边用浏览器上网,同时又可以听歌,还能再撩个×××姐,这就是多任务,操作系统会轮流把系统调度到每个核心上去执行 并发和并行 并发是指任务数多余cpu核数,通过操作系统的...
    99+
    2023-01-31
    Python
  • Python全栈开发之网络编程
    No.1 TCP/IP 早期的计算机网络,都是由厂商规定自己的通信协议,互不兼容,为了把全世界不同类型的计算机连接起来,就必须规定一套全球通用的协议,所以就出现了TCP/IP No.2 Socket简介 要解决怎么标识一个进制,在一台电...
    99+
    2023-01-31
    网络编程 Python
  • Python全栈开发之---assert
    一、python assert的作用: 根据Python 官方文档解释(https://docs.python.org/3/reference/simple_stmts.html#assert), "Assert statements a...
    99+
    2023-01-30
    Python assert
  • Python全栈开发之Git
    No.1 Git 特点 版本控制:可以解决多人同时开发的代码问题,也可以找回历史代码 分布式:Git是一个分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上,首先会有一台计算机充当服务器,这台计算机7*24小时服务,其他计算机都...
    99+
    2023-01-31
    Python Git
  • Python全栈开发之---mysql数
    1、数据库的安装和连接 1 #数据库安装 2 pip install PyMySQL 3 4 #数据库操作 5 import pymysql 6 7 db = pymysql.connect("数据库ip","用户",...
    99+
    2023-01-30
    Python mysql
  • Python全栈开发之函数
    No.1 函数介绍 所谓函数,就是把具有独立功能的代码块组织为一个小模块,在需要的时候调用 函数的使用有两个步骤:1、定义函数2、调用函数 函数的作用,代码重用,提高开发效率 No.2 定义和调用 定义函数的格式如下: def 函数名():...
    99+
    2023-01-31
    函数 Python
  • python全栈开发之Python基础(
    一、 基础知识 python的运行方式有两种: 第一种通过交互式的运行方式,通过 "开始"—>"所有程序" —> "python3.x" —>"IDLE" 运行。 第二种是我们写好的Python文件双击运行。 ...
    99+
    2023-01-31
    基础 python Python
  • Python全栈开发之Django进阶
    No.1 静态文件处理 项目中CSS、JS、图片都属于静态文件,一般会将静态文件存到一个单独目录中,便于管理,在HTML页面调用时,需要指定静态文件的路径,Django提供了一种解析静态文件的机制,文件可以放在项目目录下,也可以放在应用目录...
    99+
    2023-01-31
    进阶 Python Django
  • Python全栈开发之---装饰器
    1、装饰器的形成过程 1 import time 2 3 def func1(): 4 print('in func1') 5 6 def timer(func): 7 def inner(): 8...
    99+
    2023-01-30
    Python
  • Python全栈开发之Django基础
    No.1 MVC&MTV MVC M全拼为Model,主要封装对数据库层的访问,对数据库中的数据进行增、删、改、查操作 V全拼为View,用于封装结果,生成页面展示的html内容 C全拼为Controller,用于接收请求,处理业务...
    99+
    2023-01-31
    基础 Python Django
  • Python全栈开发之常用模块
    No.1 sys sys模块是与Python解释器交互的一个接口 sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit(0),错误退出sys.exit(1) sys.vers...
    99+
    2023-01-31
    模块 常用 Python
  • Python全栈开发之文件操作
    No.1 文件的概念 文件的概念和作用 计算机中的文件,就是存储在某种长期储存设备上的一段数据流 计算机中的文件,可以在需要的时候使用 文件的存储方式 文本文件 可以使用文本编辑器查看 本质上还是二进制文件 二进制文件 保留的内容不能直接...
    99+
    2023-01-31
    操作 文件 Python
  • Python全栈开发之面向对象
    No.1 概念 面向对象的特点? 注重对象和指责,不同的对象承担各自的指责 更加适合对复杂的需求变化,专门应对复杂项目开发,提供固定的套路 面向对象强调的是谁来做,面向过程强调的如何做 什么是类 类是对一群具有相同特征或者行为的事物统称,是...
    99+
    2023-01-31
    面向对象 Python
  • Python全栈开发之基础语法
    No.1 Python语言介绍 详情见百度百科。。。 No.2 Python是一门怎么样的语言 详情在百度百科。。。 No.3 Python能做什么 网络应用、桌面应用、系统运维、机器学习、科学计算。。。 网络应用 Django/Flas...
    99+
    2023-01-31
    语法 基础 Python
  • Python全栈开发之异常处理
    No.1 异常的概念 程序在运行过程中,遇到一个错误,会停止程序的运行,并且提示一些错误信息,这就是异常 程序停止执行并且提示错误信息这个动作,称为抛出异常 No.2 捕获异常 简单捕获异常格式 捕获异常最简单的语法格式: try: ...
    99+
    2023-01-31
    异常 Python
  • Python并发编程之协程
    协程介绍 协程:是单线程下的并发,又称微线程,纤程。协程是一种用户态的轻量级线程,即线程是由用户程序自己控制调度的。 需要强调的是: #1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫...
    99+
    2023-01-30
    Python
  • python并发编程之多进程
    阅读目录 一 multiprocessing模块介绍 二 Process类的介绍 三 Process类的使用 四 守护进程 一  multiprocessing模块介绍  python中的多线程无法利用多核优势,如果想...
    99+
    2023-01-30
    之多 进程 python
  • python并发编程之多线程编程
    一、threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 二、开启线程的两种方式 方式一: from threading import ...
    99+
    2023-01-31
    之多 线程 python
  • Java并发编程之线程安全性
    目录1.什么是线程安全性2.原子性2.1 竞争条件2.2 复合操作3.加锁机制3.1 内置锁3.2 重入4.用锁保护状态5.活跃性与性能1.什么是线程安全性 当多个线程访问某个类时,...
    99+
    2022-11-13
  • python基础之并发编程(一)
    目录一、进程(Process)二、线程(Thread)三、并发编程解决方案:四、多线程实现 (两种)1、第一种 函数方法2、第二种 类方法包装五、守护线程与子线程1、线程在分法有:2...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作