http://www.cnblogs.com/yuanchenqi/articles/6248025.html  博客地址

本节内容:

1:进程和线程的说明

2:线程的两种调用方式

3:threading.thread的实例方法

4:python的GIL

5:互斥锁Lock

6:递归锁Rlock

7:Semaphore锁

8:同步条件event

9:队列

1:进程和线程的说明

  1. 进程一般由程序、数据集、进程控制块三部分组成。
  2. 我们编写的程序用来描述进程要完成哪些功能以及如何完成;
  3. 数据集则是程序在执行过程中所需要使用的资源;
  4. 进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
  5.  
  6. 线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。

进程和线程的大白话

  1. 进程:本质上就是程序运行的实例
  2.  
  3. 进程和进程之前的数据是不能共享的。
  4. 线程和线程之间可以共享。
  5.  
  6. 比如说你开一个qqqq就是qq程序执行的实例,是进程。而qq里面的功能就是各个线程。

2.线程的两种调用方式

threading 模块建立在thread 模块之上。thread模块以低级、原始的方式来处理和控制线程,而threading 模块通过对thread进行二次封装,

提供了更方便的api来处理线程。

直接调用:

  1. import threading
  2. import time
  3.  
  4. def sayhi(num): #定义每个线程要运行的函数
  5.  
  6. print("running on number:%s" %num)
  7.  
  8. time.sleep()
  9.  
  10. if __name__ == '__main__':
  11.  
  12. t1 = threading.Thread(target=sayhi,args=(,)) #生成一个线程实例
  13. t2 = threading.Thread(target=sayhi,args=(,)) #生成另一个线程实例
  14.  
  15. t1.start() #启动线程
  16. t2.start() #启动另一个线程
  17.  
  18. print(t1.getName()) #获取线程名
  19. print(t2.getName())

继承式调用:(ps没多大用,一般直接调用就好)

  1. import threading
  2. import time
  3.  
  4. class MyThread(threading.Thread):
  5. def __init__(self,num):
  6. threading.Thread.__init__(self)
  7. self.num = num
  8.  
  9. def run(self):#定义每个线程要运行的函数
  10.  
  11. print("running on number:%s" %self.num)
  12.  
  13. time.sleep()
  14.  
  15. if __name__ == '__main__':
  16.  
  17. t1 = MyThread()
  18. t2 = MyThread()
  19. t1.start()
  20. t2.start()
  21.  
  22. print("ending......")

3.threading.thread的实例方法

 join方法:

当线程对象采用join的时候,必须先执行完当前的子线程,主线程才可以工作;而子线程之间没有这个关系。

join():在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

  1. import threading
  2. import time
  3.  
  4. def music():
  5. print("begin to listen %s"%time.ctime())
  6. time.sleep()
  7. print("end to listen %s" % time.ctime())
  8.  
  9. def game():
  10. print("begin to game %s"%time.ctime())
  11. time.sleep()
  12. print("end to game %s" % time.ctime())
  13.  
  14. if __name__ == "__main__":
  15. t1 = threading.Thread(target=music) ##开启了一个线程
  16.  
  17. t2 = threading.Thread(target=game) ##开启第二个线程
  18. t2.start()
  19. t1.start()
  20. t1.join() ##t1不执行完,主线程不能走
  21. t2.join() ##
  22. print("end.......")
  23.  
  24. ##输出 bengin game 和 listen同时打印出来,过了三秒end game再打印出来,等再过2秒打印出end listen 和 end....
  25. # begin to game Sat Mar ::
  26. # begin to listen Sat Mar ::
  27. # end to game Sat Mar ::
  28. # end to listen Sat Mar ::
  29. # end.......

setDaemon 守护线程

  1. import threading
  2. import time
  3.  
  4. def f1(i):
  5. time.sleep()
  6. print(i)
  7.  
  8. if __name__ == '__main__':
  9. for i in range():
  10. t = threading.Thread(target=f1, args=(i,))
  11. t.setDaemon(True) ##守护主线程,。只要主线程结束,就陪着一起退出
  12. t.start()
  13.  
  14. print('start') # 主线程不等待子线程
  15.  
  16. ##输出
  17. #start
  1. setDaemon(True):
  2. 将线程声明为守护线程,必须在start() 方法调用之前设置, 如果不设置为守护线程程序会被无限挂起。这个方法基本和join是相反的。
  3. 当我们 在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行,那么当主线程完成
  4. 想退出时,会检验子线程是否完成。如 果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是 只要主线程
  5. 完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 setDaemon方法啦。

其它方法

除此之外,自己还可以为线程自定义名字,通过 t = threading.Thread(target=f1, args=(i,), name='mythread{}'.format(i)) 中的name参数,除此之外,Thread还有一下一些方法

  1. # run(): 线程被cpu调度后自动执行线程对象的run方法
  2. t.start() :启动线程活动。
  3. t.getName() : 获取线程的名称
  4. t.setName() 设置线程的名称
  5. t.name : 获取或设置线程的名称
  6. t.is_alive() 判断线程是否为激活状态
  7. t.isAlive() :判断线程是否为激活状态
  8. t.isDaemon() 判断是否为守护线程
  9.  
  10. threading模块提供的一些方法:
  11. # threading.currentThread(): 返回当前的线程变量。
  12. # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  13. # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果

4.python的GIL

In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

上面的核心意思就是,无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行

GIL是存在于pythonC解释器中,你要想在python中使用多线程并行 那就别想了。java中是不存在这个锁的,但是用户需要繁琐的加锁解锁,保障线程的安全。

任务的区分:

  1. 对于IO密集型的任务,python的多线程是有意义的
  2. 对于计算密集型的任务;python的多线程不推荐,可以采用多进程+协程

并发&并行

  1. 并发:是指系统具有处理多个任务(动作)的能力 ;通俗的说就是cpu能够进行切换任务,就说具有了并发。
  2. 并行:是值系统具有同时处理多个任务(动作)的能力
  3.  
  4. 并行是并发的一个子集

同步 & 异步

  1. 现象:如上个博文所说的socket,当你等待用户或服务端的数据recv 时,就一直阻塞在那里。这叫同步
  2. 同步:当进程执行到一个IO(等待外部数据的时候),等 ---就是同步
  3. 异步:当进程执行到一个IO(等待外部数据的时候),不等 ---就是异步

5.同步锁(也叫互斥锁)

  1. ###开100个线程进行 累加或累减
  2. import threading
  3. import time
  4. def sub():
  5. global num
  6. temp = num
  7. time.sleep(0.0001)
  8. num = temp -1
  9. # num -= 1
  10.  
  11. num = 100
  12. l = []
  13. for i in range(100):
  14. t = threading.Thread(target=sub)
  15. t.start()
  16. l.append(t)
  17.  
  18. for i in l :
  19. i.join()
  20.  
  21. print(num)
  22.  
  23. # 输出: 我想要的是0 怎么给我输出了78了?
  24. #

分析:加的time.sleep()的区别就是cpu遇见了io阻塞,马上就进行切换。

大家都处理一个数据,而这个数据在进行切换的时候,数据还没执行完就进行切换,导致了同一时刻,不同的线程拿到了同一个数据。

解决办法:加同步锁

  1. import threading
  2. import time
  3. def sub():
  4. global num
  5. lock.acquire() ##将下面的代码锁起来,在我锁的过程谁都不能对下面的数据进行操作
  6. temp = num
  7. time.sleep(1) ##1秒意味着 100秒才可以出结果
  8. num = temp -1
  9. lock.release() ##释放锁
  10. # num -= 1
  11.  
  12. num = 100
  13. l = []
  14. lock = threading.Lock() ###创建了一把锁
  15. for i in range(100):
  16. t = threading.Thread(target=sub)
  17. t.start()
  18. l.append(t)
  19.  
  20. for i in l :
  21. i.join()
  22.  
  23. print(num)
  24.  
  25. # 输出:
  26. #
  1. def sub():
  2. global num
  3. print('ok')
  4. time.sleep(1)
  5. print('ok2')
  6. lock.acquire() ##将下面的代码锁起来,在我锁的过程谁都不能对下面的数据进行操作
  7. temp = num
  8. time.sleep(0.01) ##1秒意味着 100秒才可以出结果
  9. num = temp -1
  10. lock.release() ##释放锁
  11.  
  12. ##我串行的部分就是 lock的三行部分 其他的还是 并行的,

6.死锁锁、递归锁

同步锁的缺点:

在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去。下面是一个死锁的例子:

死锁实例:

  1. import threading
  2. import time
  3.  
  4. class MyThread(threading.Thread):
  5. def actionA(self):
  6. A.acquire()
  7. print(self.name,"GotA",time.ctime()) ###self 是一个线程对象,打印出线程名字
  8. time.sleep(2)
  9.  
  10. B.acquire()
  11. print(self.name, "GotB", time.ctime())
  12. time.sleep(2)
  13. B.release() ##释放B锁
  14. A.release() ##释放A锁
  15.  
  16. def actionB(self):
  17. B.acquire()
  18. print(self.name, "GotB", time.ctime()) ###self 是一个线程对象,打印出线程名字
  19. time.sleep(1)
  20.  
  21. A.acquire()
  22. print(self.name, "GotA", time.ctime())
  23. A.release() ##释放A锁
  24. B.release() ##释放B锁
  25.  
  26. def run(self):
  27. self.actionA()
  28. self.actionB()
  29.  
  30. if __name__ == '__main__':
  31.  
  32. ##创建两把锁
  33. A = threading.Lock()
  34. B = threading.Lock()
  35. L = []
  36. for i in range(5):
  37. t = MyThread()
  38. t.start()
  39. L.append(t)
  40.  
  41. for i in L:
  42. i.join()
  43.  
  44. print('ending.........')
  45.  
  46. ##5个线程一起走都要获取到lock a ,线程1拿到了a 其他四个都要等待,线程1 释放 a锁才能进来,
  47. #线程1
  48.  
  49. # 输出:
  50. # Thread-1 GotA Sun Mar 18 12:07:12 2018
  51. # Thread-1 GotB Sun Mar 18 12:07:14 2018
  52. # Thread-1 GotB Sun Mar 18 12:07:16 2018
  53. # Thread-2 GotA Sun Mar 18 12:07:16 2018

解决办法 递归锁(Rlock):

由于线程是共享同一份内存的,所以如果操作同一份数据,很容易造成冲突,这时候就可以为线程加上一个锁了,这里我们使用Rlock,而不使用Lock,因为Lock如果多次获取锁的时候会出错,而RLock允许在同一线程中被多次acquire,但是需要用n次的release才能真正释放所占用的琐,一个线程获取了锁在释放之前,其他线程只有等待。

  1. import threading
  2. import time
  3.  
  4. class MyThread(threading.Thread):
  5. def actionA(self):
  6. rlock.acquire()
  7. print(self.name,"GotA",time.ctime()) ###self 是一个线程对象,打印出线程名字
  8. time.sleep(2)
  9.  
  10. rlock.acquire()
  11. print(self.name, "GotB", time.ctime())
  12. time.sleep(2)
  13. rlock.release() ##释放B锁
  14. rlock.release() ##释放A锁
  15.  
  16. def actionB(self):
  17. rlock.acquire()
  18. print(self.name, "GotB", time.ctime()) ###self 是一个线程对象,打印出线程名字
  19. time.sleep(1)
  20.  
  21. rlock.acquire()
  22. print(self.name, "GotA", time.ctime())
  23. rlock.release() ##释放A锁
  24. rlock.release() ##释放B锁
  25.  
  26. def run(self):
  27. self.actionA()
  28. self.actionB()
  29.  
  30. if __name__ == '__main__':
  31.  
  32. ##创建两把锁
  33. # A = threading.Lock()
  34. # B = threading.Lock()
  35. L = []
  36. ##创建递归锁
  37. rlock = threading.RLock()
  38. for i in range(5):
  39. t = MyThread()
  40. t.start()
  41. L.append(t)
  42.  
  43. for i in L:
  44. i.join()
  45.  
  46. print('ending.........')
  47.  
  48. ##5个线程一起走都要获取到lock a ,线程1拿到了a 其他四个都要等待,线程1 释放 a锁才能进来,
  49. #线程1
  50.  
  51. # 输出:
  52. # Thread-1 GotA Sun Mar 18 12:17:52 2018
  53. # Thread-1 GotB Sun Mar 18 12:17:54 2018
  54. # Thread-1 GotB Sun Mar 18 12:17:56 2018
  55. # Thread-1 GotA Sun Mar 18 12:17:57 2018
  56. # Thread-3 GotA Sun Mar 18 12:17:57 2018
  57. # Thread-3 GotB Sun Mar 18 12:17:59 2018
  58. # Thread-3 GotB Sun Mar 18 12:18:01 2018
  59. # Thread-3 GotA Sun Mar 18 12:18:02 2018
  60. # Thread-5 GotA Sun Mar 18 12:18:02 2018
  61. # Thread-5 GotB Sun Mar 18 12:18:04 2018
  62. # Thread-2 GotA Sun Mar 18 12:18:06 2018
  63. # Thread-2 GotB Sun Mar 18 12:18:08 2018
  64. # Thread-2 GotB Sun Mar 18 12:18:10 2018
  65. # Thread-2 GotA Sun Mar 18 12:18:11 2018
  66. # Thread-5 GotB Sun Mar 18 12:18:11 2018
  67. # Thread-5 GotA Sun Mar 18 12:18:12 2018
  68. # Thread-4 GotA Sun Mar 18 12:18:12 2018
  69. # Thread-4 GotB Sun Mar 18 12:18:14 2018
  70. # Thread-4 GotB Sun Mar 18 12:18:16 2018
  71. # Thread-4 GotA Sun Mar 18 12:18:17 2018
  72. # ending.........

递归锁的,内部就是维护 了一个计算器默认是0,当有人用rlock 就+1,直到rlock = 0 才能继续,让线程竞争锁,谁抢到谁执行。

7:Semaphore锁

Semaphore锁也是锁的一种,类似于停车场 ,停车场一次可以停3辆车,当第三辆车来了之后,只能等待前面三辆车离开大于等于1辆 才能进入。

实例:

  1. import threading
  2. import time
  3.  
  4. class MyThread(threading.Thread):
  5. def run(self):
  6. if more.acquire(): ##加锁 当停车场小于三的时候,车进入
  7. time.sleep()
  8. print(self.name)
  9. more.release() ## 解锁,车离开 允许后面的车进来
  10.  
  11. more = threading.Semaphore() ##默认停车场三辆
  12.  
  13. l = []
  14. for i in range():
  15. t = MyThread()
  16. t.start()
  17. l.append(t)
  18.  
  19. for i in l:
  20. i.join()
  21.  
  22. print('end........')
  23.  
  24. # 输出: 没三秒输出三个线程
  25. # Thread-
  26. # Thread-
  27. # Thread-
  28.  
  29. # Thread-
  30. # Thread-
  31. # Thread-

8:同步条件event

在之前不管是加锁还是其他的,线程都是处于竞争的,谁抢到cpu就执行谁。而达不到一个相互协调工作的情况。

event的原理很简单:就是线程之间共同围绕着一个标志位,当线程A没有set标志位的时候,线程B阻塞住。当线程A set标志位的时候,让B线程执行。

达到一个同步的效果:

就三个方法记住:

# a client thread can wait for the flag to be set
event.wait()

# a server thread can set or reset it
event.set()
event.clear()

  1. import threading,time
  2. class Boss(threading.Thread):
  3. def run(self):
  4. print("BOSS:今晚大家都要加班到22:00。")
  5. print(event.isSet())
  6. event.set()
  7. time.sleep(5)
  8. print("BOSS:<22:00>可以下班了。")
  9. print(event.isSet())
  10. event.set()
  11. class Worker(threading.Thread):
  12. def run(self):
  13. event.wait() ##boss没set 就阻塞住,一但boss set开始执行
  14. print("Worker:哎……命苦啊!")
  15. time.sleep(1)
  16. event.clear()
  17. event.wait()
  18. print("Worker:OhYeah!")
  19. if __name__=="__main__":
  20. event=threading.Event()
  21. threads=[]
  22. for i in range(5): ##创建5个work
  23. threads.append(Worker())
  24. threads.append(Boss()) ##创建一个Boss
  25. for t in threads:
  26. t.start()
  27. for t in threads:
  28. t.join()
  29.  
  30. # 输出:
  31. # BOSS:今晚大家都要加班到22:00。
  32. # False
  33. # Worker:哎……命苦啊!
  34. # Worker:哎……命苦啊!
  35. # Worker:哎……命苦啊!
  36. # Worker:哎……命苦啊!
  37. # Worker:哎……命苦啊!
  38. # BOSS:<22:00>可以下班了。
  39. # False
  40. # Worker:OhYeah!
  41. # Worker:OhYeah!
  42. # Worker:OhYeah!
  43. # Worker:OhYeah!
  44. # Worker:OhYeah!

9.队列Queue

队列是一种数据结构,不懂什么是数据结构?

数据结构就是帮你存储数据的一种格式,比如说列表 是按一个个索引值去存储数据,而字典是通过哈希给你存储数据。

为什么要有队列?

之所以会出现队列是因为遇见了多线程,它保证了数据的安全。

创建队列对象

  1. import queue
  2.  
  3. q = queue.Queue()
  4. q = queue.Queue(5) ##就表示创建了一个5个格子的队列

创建一个队列对象就类似创建了这样的一个格子,接下来我们就要往里面添值。

添值

  1. q.put(12)
  2. q.put('hi')
  3. q.put([1,3,4])

获取值

  1. while 1 :
  2. data = q.get()
  3. print(data)

输出:

  1. 12
  2. hi
  3. [1, 3, 4]

完整代码

  1. import queue
  2.  
  3. q = queue.Queue()
  4.  
  5. q.put()
  6. q.put('hi')
  7. q.put([,,])
  8.  
  9. while :
  10. data = q.get()
  11. print(data)

我们说创建了一个格子,那么开始是怎么放置值的?

  1. 先进先出队列 queue.Queue()
  2. 后进先出队列 queue.LifoQueue()
  3. 按优先级队列 queue.PriorityQueue()
  1. import queue
  2.  
  3. # q = queue.Queue()
  4. q = queue.LifoQueue()
  5. # q = queue.PriorityQueue()
  6.  
  7. q.put()
  8. q.put('hi')
  9. q.put([,,])
  10.  
  11. while :
  12. data = q.get()
  13. print(data)
  14.  
  15. # 输出:
  16. # [, , ]
  17. # hi
  18. #

后进先出

数据越小优先级越高

  1. import queue
  2.  
  3. q = queue.PriorityQueue()
  4.  
  5. q.put([,'hi'])
  6. q.put([,])
  7. q.put([,[,,]])
  8.  
  9. while :
  10. data = q.get()
  11. # print(data)
  12. print(data[])
  13.  
  14. # 输出: 默认输出的是一个列表
  15. # [, 'hi']
  16. # [, ]
  17. # [, [, , ]]
  18.  
  19. # hi
  20. #
  21. # [, , ]

优先级队列

其他的一些方法

  1. q.qsize() 返回队列的大小
  2. q.empty() 如果队列为空,返回True,反之False
  3. q.full() 如果队列满了,返回True,反之False
  4. q.full maxsize 大小对应
  5. q.get([block[, timeout]]) 获取队列,timeout等待时间
  6. q.get_nowait() 相当q.get(False) ##不等待程序往队列放值,直接报错
  7. 非阻塞 q.put(item) 写入队列,timeout等待时间
  8. q.put_nowait(item) 相当q.put(item, False) ##当队列满了,阻塞住程序,直到队列get出去,此方法表示不等待,直接报错
  9. q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
  10. q.join() 实际上意味着等到队列为空,再执行别的操作

  

 

Day12- Python基础12 线程、GIL、Lock锁、RLock锁、Semaphore锁、同步条件event的更多相关文章

  1. Python 基础之 线程与进程

    Python 基础之 线程与进程 在前面已经接触过了,socket编程的基础知识,也通过socketserver 模块实现了并发,也就是多个客户端可以给服务器端发送消息,那接下来还有个问题,如何用多线 ...

  2. 十二. Python基础(12)--生成器

    十二. Python基础(12)--生成器 1 ● 可迭代对象(iterable) An object capable of returning its members one at a time. ...

  3. 『Python基础-12』各种推导式(列表推导式、字典推导式、集合推导式)

    # 『Python基础-12』各种推导式(列表推导式.字典推导式.集合推导式) 推导式comprehensions(又称解析式),是Python的一种独有特性.推导式是可以从一个数据序列构建另一个新的 ...

  4. 《python基础教程(第二版)》学习笔记 语句/循环/条件(第5章)

    <python基础教程(第二版)>学习笔记 语句/循环/条件(第5章) print 'AB', 123 ==> AB 123 # 插入了一个空格print 'AB', 'CD' == ...

  5. Python学习---同步条件event/队列queue1223

    写在前面: 在使用这些共享API的时候,我们要注意以下几点: 在UNIX平台上,当某个进程终结之后,该进程需要被其父进程调用wait,否则进程成为僵尸进程(Zombie).所以,有必要对每个Proce ...

  6. python基础-12 多线程queue 线程交互event 线程锁 自定义线程池 进程 进程锁 进程池 进程交互数据资源共享

    Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...

  7. python网络编程--线程GIL(全局解释器锁)

    一:什么是GIL 在CPython,全局解释器锁,或GIL,是一个互斥体防止多个本地线程执行同时修改同一个代码.这把锁是必要的主要是因为当前的内存管理不是线程安全的.(然而,由于GIL存在,其他特性已 ...

  8. python基础(34):线程(二)

    1. python线程 1.1 全局解释器锁GIL Python代码的执行由Python虚拟机(也叫解释器主循环)来控制.Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行.虽然 Py ...

  9. python基础之线程、进程、协程

    线程 线程基础知识 一个应用程序,可以多进程.也可以多线程. 一个python脚本,默认是单进程,单线程的. I/O操作(音频.视频.显卡操作),不占用CPU,所以: 对于I/O密集型操作,不会占用C ...

随机推荐

  1. Docker + WordPress搭建个人博客

    WordPress是目前非常受欢迎的开源博客系统,今天使用Docker + WordPress搭建个人博客,整个过程非常丝滑. 搭博客先要准备域名和服务器,昨天在阿里云买了个.top的域名花了5块钱( ...

  2. 基于Git的数据库sql文件的管理——完美解决团队sql操作协同问题

    目录 基于Git的数据库sql文件的管理--完美解决团队sql操作协同问题 1.产生背景 2.之前没用Git管理数据库出现的问题 2.1 用同一个库调试带来的问题 3.解决方案 3.1 Sql文件的创 ...

  3. 卡拉OK歌词原理和实现高仿Android网易云音乐

    大家好,我们是爱学啊,继上一篇讲解了[LRC歌词原理和实现高仿Android网易云音乐],今天给大家带来一篇关于卡拉OK歌词原理和在Android上如何实现歌词逐字滚动的效果,本文来自[Android ...

  4. openldap数据备份还原

    数据备份[root@Server ~]# slapcat -n 2 -l /root/ldapbackup_ilanni.ldif脚本 ----- #!/bin/bash # 备份脚本 PATH=&q ...

  5. ASCII码表收藏

    ASCII码表 ASCII码值 ESC键 VK_ESCAPE (27)回车键: VK_RETURN (13)TAB键: VK_TAB (9)Caps Lock键: VK_CAPITAL (20)Shi ...

  6. acwing 849 Dijkstra求最短路 I 模板

    地址 https://www.acwing.com/problem/content/description/851/ 给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为正值. 请你求出 ...

  7. vue-property-decorator和typescript结合构建的class类组件,父组件触发子组件方法的方式

    vue-property-decorator和typescript结合构建的class类组件,父组件触发子组件方法的方式 class类组件示例 Father类组件 <template> & ...

  8. SpringCloud gateway (史上最全)

    疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之 -25[ 博客园 总入口 ] 前言 ### 前言 疯狂创客圈(笔者尼恩创建的高并发研习社群)Springcloud 高并发系列文章,将为大家 ...

  9. 前端小白webpack学习(一)

    俗话说得好,好记性不如烂笔头. 之前就在学习中看过webpack的教程,然而一段时间没用,火速的忘光了.写这篇博文,做个总结,也让自己以后有个地方回顾. 看webpack之前,我先去看了一下官方文档, ...

  10. Failed to execute ‘createObjectURL’ on ‘URL’: No function was found that matched the signature provided.

    这个报错是因为在浏览器上开启了手机模拟调试.Web SDK 不支持手机模拟调试的.