一、什么是线程?什么是进程?

  1. 第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
  2. 第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。[3]
  3. 进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。
  4.  
  5. 进程的概念

进程的定义

  1. 线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
  2.  
  3. 在单个程序中同时运行多个线程完成不同的工作,称为多线程。

线程定义

  1. 协程,是由程序员创造出来的一个不是真实存在的东西;可以看做是一个微线程,对一个线程进程分片,使得线程在代码块之间进行来回切换执行,而不是在逐行执行。

协程定义

注意:

  对于python而言,其自己没有进程和线程,在执行的时候需要调用操作系统的进程和线程。

二、应用软件、进程和线程的关系

程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行。这是这样的设计,大大提高了CPU的利用率。进程的出现让每个用户感觉到自己独享CPU,因此,进程就是为了在CPU上实现多道编程而提出的。

  简单来说:一个应用程序(软件),可以有多个进程(默认只有一个),一个进程中可以创建多个线程(默认一个)。

三、进程、线程、协程的区别

进程是资源分配的最小单元,其作用是进行数据隔离,线程是cpu调度的最小单元,其作用主要是执行某个任务,一个应用程序可以有多个进程,一个进程可以有多个线程,在其他语言中几乎很少用进程,都是用多线程,而对于python来说,IO操作主要是用多线程实现,计算密集型操作主要是用多进程实现,主要原因是python中存在GIL锁,GIL锁的作用就是保证一个进程中同一时刻只有一个线程被cpu调度,所以在python中想要利用cpu的多核优势就是开多个进程。在后来程序员级别的人为了让代码更牛逼,创建了一个东西叫协程,这个东西本身不存在,是程序员自己创造出来的,协程可以对代码的执行顺序进行控制,本身这个东西存在没有意义,但是协程要是和IO切换放在一起就了不得了,遇到IO操作就切换,相当于把一个线程分片,所达到的效果是线程一直没有停,一直在工作,这就是进程、线程、协程的本质区别,在python中用协程的时候会有一个模块叫greenlet,协程加IO自动切换的模块叫gevent。

  1. 注意:IO密集型操作可以使用多线程;计算密集型可以使用多进程;
    *****通过漫画了解进程与线程

四、线程

  (一)线程的基本使用

  1. #主程序默认等待子程序执行完毕
  2. import threading
  3. import time
  4. def func(arg):
  5. time.sleep(arg)
  6. print(arg)
  7.  
  8. t1 = threading.Thread(target=func,args=(3,))
  9. t1.start()
  10.  
  11. t2 = threading.Thread(target=func,args=(2,))
  12. t2.start()
  13.  
  14. print(123)

  (二)线程的常用方法

  1、start     线程准备就绪,等待CPU调度

  2、setDaemon(True)  主程序不再等,主程序终止则所有子程序终止

  1. import threading
  2. import time
  3. def func(arg):
  4. time.sleep(2)
  5. print(arg)
  6.  
  7. t1 = threading.Thread(target=func,args=(3,))
  8. t1.setDaemon(True) #设置主程序不在等待子程序执行完毕,主程序终止则子程序终止
  9. t1.start()
  10.  
  11. t2 = threading.Thread(target=func,args=(9,))
  12. t2.setDaemon(True)
  13. t2.start()
  14.  
  15. print(123)

  3、join  开发者可以控制主线程等待子线程(最多等待时间)

  1. import threading
  2. import time
  3. def func(arg):
  4. time.sleep(arg)
  5. print(arg)
  6.  
  7. print('创建子线程t1')
  8. t1 = threading.Thread(target=func,args=(3,))
  9. t1.start()
  10. # join()无参数,让主线程在这里等着,等到子线程t1执行完毕,才可以继续往下走。
  11. # join(n)有参数,让主线程在这里最多等待n秒,无论是否执行完毕,会继续往下走,但最终会等所有子程序执行完毕主程序在终止。
  12. t1.join(6)
  13.  
  14. print('创建子线程t2')
  15. t2 = threading.Thread(target=func,args=(6,))
  16. t2.start()
  17. t2.join(6)
  18.  
  19. print(123)

  4、其它方法

  1. import threading
  2. import time
  3. def func(arg):
  4. # 获取当前执行该函数的线程的对象
  5. t = threading.current_thread()
  6. # 根据当前线程对象获取当前线程名称
  7. name = t.getName()
  8. print(name,arg)
  9.  
  10. t1 = threading.Thread(target=func,args=(11,))
  11. t1.setName('线程1') #设置线程名称
  12. t1.start()
  13.  
  14. t2 = threading.Thread(target=func,args=(22,))
  15. t2.setName('线程2') #设置线程名称
  16. t2.start()
  17.  
  18. print(123)

  (三)两种方法创建多线程

  #多线程方式一(常见):

  1. import threading
  2. def func(arg):
  3. print(arg)
  4.  
  5. for i in range(4):
  6. t = threading.Thread(target=func,args=(i,))
  7. t.start()

  #多线程方式二(通过面向对象创建):

  1. import threading
  2. class MyThread(threading.Thread):
  3.  
  4. def run(self):
  5. print(11111,self._args,self._kwargs)
  6.  
  7. t1 = MyThread(args=(11,))
  8. t1.start()
  9.  
  10. t2 = MyThread(args=(22,))
  11. t2.start()

  (四)几种常见的线程锁

  问题:为什么要加线程锁?

  #如果不加锁就可能出现多个线程抢占资源的情况,从而出现脏数据,加上锁之后可以保证在同一时刻只有一个线程在执行。

  *****同步锁******

  1. import threading
  2. import time
  3. lock = threading.Lock()
  4. v = []
  5. def task(i):
  6. lock.acquire()
  7. v.append(i)
  8. time.sleep(0.01)
  9. m = v[-1]
  10. print(m,i)
  11. lock.release()
  12. for i in range(10):
  13. t = threading.Thread(target=task,args=(i,))
  14. t.start()

Lock

  *****递归锁:可以多次获得锁,多次释放锁******

  1. import threading
  2. import time
  3. lock = threading.RLock()
  4. v = []
  5. def task(i):
  6. lock.acquire()
  7. lock.acquire()
  8. v.append(i)
  9. time.sleep(0.01)
  10. m = v[-1]
  11. print(m,i)
  12. lock.release()
  13. lock.release()
  14. for i in range(10):
  15. t = threading.Thread(target=task,args=(i,))
  16. t.start()

RLock

  *****信号锁:可以控制一次最多有n个线程执行代码******

  1. import threading
  2. import time
  3. lock = threading.BoundedSemaphore(5)
  4. def task(i):
  5. lock.acquire()
  6. print(i)
  7. time.sleep(1)
  8. lock.release()
  9. for i in range(10):
  10. t = threading.Thread(target=task,args=(i,))
  11. t.start()

BoundedSemaphore

  *****条件锁:简单理解,满足条件时,释放线程,根据输入数量释放相应的线程数量******

  1. import threading
  2. import time
  3. lock = threading.Condition()
  4. def task(i):
  5. print('线程来了',i)
  6. lock.acquire()
  7. lock.wait()
  8. print(i)
  9. time.sleep(1)
  10. lock.release()
  11.  
  12. for i in range(10):
  13. t = threading.Thread(target=task,args=(i,))
  14. t.start()
  15. while 1:
  16. num = int(input('请输入一次要执行的线程数量>>>'))
  17. lock.acquire()
  18. lock.notify(num)
  19. lock.release()

Condition

  *****事件锁:一次放所有线程******

  1. import threading
  2. import time
  3. lock = threading.Event()
  4. def task(i):
  5. print('线程来了')
  6. lock.wait() #“Flag”值为False
  7. print(i)
  8. time.sleep(1)
  9. for i in range(10):
  10. t = threading.Thread(target=task,args=(i,))
  11. t.start()
  12. input('>>>')
  13. lock.set() #“Flag”值为True
  14. lock.clear #“Flag”值为False

Event

  (五)线程池

  1. from concurrent.futures import ThreadPoolExecutor
  2. import time
  3.  
  4. def task(a1,a2):
  5. time.sleep(2)
  6. print(a1,a2)
  7.  
  8. # 创建了一个线程池(最多5个线程)
  9. pool = ThreadPoolExecutor(5)
  10.  
  11. for i in range(40):
  12. # 去线程池中申请一个线程,让线程执行task函数。
  13. pool.submit(task,i,8)

  (六)生产者消费者模型

  1. import time
  2. import queue
  3. import threading
  4. q = queue.Queue() # 线程安全
  5.  
  6. def producer(id):
  7. """
  8. 生产者
  9. :return:
  10. """
  11. while True:
  12. time.sleep(2)
  13. q.put('包子')
  14. print('厨师%s 生产了一个包子' %id )
  15.  
  16. for i in range(1,4):
  17. t = threading.Thread(target=producer,args=(i,))
  18. t.start()
  19.  
  20. def consumer(id):
  21. """
  22. 消费者
  23. :return:
  24. """
  25. while True:
  26. time.sleep(1)
  27. v1 = q.get()
  28. print('顾客 %s 吃了一个包子' % id)
  29.  
  30. for i in range(1,3):
  31. t = threading.Thread(target=consumer,args=(i,))
  32. t.start()

  (七)threadinglocal 原理

作用:为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离)。

  1. import time
  2. import threading
  3. INFO = {}
  4. class Local(object):
  5.  
  6. def __getattr__(self, item):
  7. ident = threading.get_ident()
  8. return INFO[ident][item]
  9.  
  10. def __setattr__(self, key, value):
  11. ident = threading.get_ident()
  12. if ident in INFO:
  13. INFO[ident][key] = value
  14. else:
  15. INFO[ident] = {key:value}
  16.  
  17. obj = Local()
  18. def func(arg):
  19. obj.phone = arg # 调用对象的 __setattr__方法(“phone”,1)
  20. time.sleep(2)
  21. print(obj.phone,arg)
  22.  
  23. for i in range(10):
  24. t =threading.Thread(target=func,args=(i,))
  25. t.start()

易理解版本

  1. import time
  2. import threading
  3.  
  4. class Local(object):
  5. def __init__(self):
  6. object.__setattr__(self,'INFO',{})
  7. def __getattr__(self, item):
  8. ident = threading.get_ident()
  9. return self.INFO[ident][item]
  10.  
  11. def __setattr__(self, key, value):
  12. ident = threading.get_ident()
  13. if ident in self.INFO:
  14. self.INFO[ident][key] = value
  15. else:
  16. self.INFO[ident] = {key:value}
  17.  
  18. obj = Local()
  19. def func(arg):
  20. obj.phone = arg # 调用对象的 __setattr__方法(“phone”,1)
  21. time.sleep(2)
  22. print(obj.phone,arg)
  23.  
  24. for i in range(10):
  25. t =threading.Thread(target=func,args=(i,))
  26. t.start()

改装版

五、进程

  (一)进程的常用功能----------------其方法和线程类似

  1. - join
    - daemon
    - name
    - multiprocessing.current_process()
    - multiprocessing.current_process().ident/pid
  1. import time
  2. import multiprocessing
  3. def task(arg):
  4. # time.sleep(3)
  5. print(arg)
  6. p = multiprocessing.current_process() #获取当前工作进程
  7. print(p.name) #获取进程名称
  8.  
  9. if __name__ == '__main__':
  10. p1 = multiprocessing.Process(target=task,args=(1,))
  11. p1.name = 'pp1' #设置进程名称
  12. p1.daemon=True #主进程执行完毕所有子进程不论执行到哪里都关闭
  13. p1.start()
  14. # p1.join(0.5) #加参数主进程最长等待子进程0.5秒就向下执行,但最终都会等子进程执行完毕在关闭
  15.  
  16. print(1234)
  17.  
  18. p2 = multiprocessing.Process(target=task, args=(2,))
  19. p2.name = 'pp2' #设置进程名称
  20. p2.daemon=True
  21. p2.start()
  22. # p2.join(0.5)
  23. print(2345)

进程常用方法

  (二)进程的数据共享问题

  进程之间的数据默认不共享,但通过Queue和Manager可以使进程之间的数据共享

  1. import multiprocessing
  2. data_list = []
  3. def task(arg):
  4. data_list.append(arg)
  5. print(data_list)
  6.  
  7. def run():
  8. for i in range(4):
  9. p = multiprocessing.Process(target=task,args=(i,))
  10. p.start()
  11.  
  12. if __name__ == '__main__':
  13. run()
  14. #结果
  15. # [2]
  16. # [0]
  17. # [1]
  18. # [3]

数据不共享

  *******进程间的数据共享:multiprocessing.Queue

  1. q = multiprocessing.Queue()
  2.  
  3. def task(arg,q):
  4. q.put(arg)
  5.  
  6. def run():
  7. for i in range(10):
  8. p = multiprocessing.Process(target=task, args=(i, q,))
  9. p.start()
  10. while True:
  11. v = q.get()
  12. print(v)
  13. if __name__ == '__main__':
  14. run()

  **********进程间的数据共享:Manager

  1. def task(arg,dic):
  2. time.sleep(2)
  3. dic[arg] = 100
  4.  
  5. if __name__ == '__main__':
  6. m = multiprocessing.Manager()
  7. dic = m.dict()
  8. process_list = []
  9. for i in range(10):
  10. p = multiprocessing.Process(target=task, args=(i,dic,))
  11. p.start()
  12. process_list.append(p)
  13.  
  14. #处理主进程和子进程数据共享问题,避免主进程结束之后共享的数据消失
  15. while True:
  16. count = 0
  17. for p in process_list:
  18. if not p.is_alive():
  19. count += 1
  20. if count == len(process_list):
  21. break
  22. print(dic)

  (三)进程锁

  参考线程锁,其使用方法及其类似

  *******为什么会有进程锁?

    当多个进程共享某个数据时,为了保证数据安全,不出现脏数据,会给进程加锁.

  (四)进程池

  1. import time
  2. from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
  3.  
  4. def task(arg):
  5. time.sleep(2)
  6. print(arg)
  7.  
  8. if __name__ == '__main__':
  9. pool = ProcessPoolExecutor(5) #进程池里面设置了5个进程
  10. for i in range(10):
  11. pool.submit(task,i)

六、简单爬虫实例--------使用线程池

  1. import requests
  2. from bs4 import BeautifulSoup
  3. from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
  4.  
  5. # 模拟浏览器发送请求
  6. # 内部创建 sk = socket.socket()
  7. # 和抽屉进行socket连接 sk.connect(...)
  8. # sk.sendall('...')
  9. # sk.recv(...)
  10.  
  11. def task(url):
  12. r1 = requests.get(
  13. url=url,
  14. headers={
  15. 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36'
  16. }
  17. )
  18.  
  19. # 查看下载下来的文本信息
  20. soup = BeautifulSoup(r1.text,'html.parser')
  21. content_list = soup.find('div',attrs={'id':'content-list'})
  22. for item in content_list.find_all('div',attrs={'class':'item'}):
  23. title = item.find('a').text.strip()
  24. target_url = item.find('a').get('href')
  25. print(title,target_url)
  26.  
  27. def run():
  28. pool = ThreadPoolExecutor(5)
  29. for i in range(1,50):
  30. pool.submit(task,'https://dig.chouti.com/all/hot/recent/%s' %i)
  31.  
  32. if __name__ == '__main__':
  33. run()

七、协程

协程的实现主要应用greenlet模块,可使线程在代码块之间来回切换执行,见代码:

  1. import greenlet
  2. def f1():
  3. print(11)
  4. gr2.switch()
  5. print(22)
  6. gr2.switch()
  7.  
  8. def f2():
  9. print(33)
  10. gr1.switch()
  11. print(44)
  12.  
  13. # 协程 gr1
  14. gr1 = greenlet.greenlet(f1)
  15. # 协程 gr2
  16. gr2 = greenlet.greenlet(f2)
  17. gr1.switch()

除了以上方法之外,也可以手动实现协程,上代码:

  1. def f1():
  2. print(11)
  3. yield
  4. print(22)
  5. yield
  6. print(33)
  7.  
  8. def f2():
  9. print(55)
  10. yield
  11. print(66)
  12. yield
  13. print(77)
  14.  
  15. v1 = f1()
  16. v2 = f2()
  17.  
  18. next(v1)
  19. next(v2)
  20. next(v1)
  21. next(v2)
  22. next(v1)
  23. next(v2)

注意:单纯的协程无用,并不能实现并发操作,但是协程遇到IO就切换就牛逼起来了,可大大缩短执行任务的等待时间,提高代码执行的速度,上代码:

  1. from gevent import monkey
  2. monkey.patch_all() # 以后代码中遇到IO都会自动执行greenlet的switch进行切换
  3. import requests
  4. import gevent
  5.  
  6. def get_page1(url):
  7. ret = requests.get(url)
  8. print(url,ret.content)
  9.  
  10. def get_page2(url):
  11. ret = requests.get(url)
  12. print(url,ret.content)
  13.  
  14. def get_page3(url):
  15. ret = requests.get(url)
  16. print(url,ret.content)
  17.  
  18. gevent.joinall([
  19. gevent.spawn(get_page1, 'https://www.python.org/'), # 协程1
  20. gevent.spawn(get_page2, 'https://www.yahoo.com/'), # 协程2
  21. gevent.spawn(get_page3, 'https://github.com/'), # 协程3
  22. ])

八、基于IO多路复用+socket实现并发请求,一个线程100个请求

  (一)IO多路复用

  1. 作用:可以监听所有的IO请求的状态。
    - socket
  2.  
  3. I,input
    o,output
  1. 操作系统检测socket是否发生变化,有三种模式:
    select:最多1024socket;循环去检测。
    poll:不限制监听socket个数;循环去检测(水平触发)。
    epoll:不限制监听socket个数;回调方式(边缘触发)。
    Python模块:
    select.select
    select.epoll
  1. 注意:windows系统只支持select
     (二)基于IO多路复用+socket实现单线程的并发,上代码:
  1. import socket
  2. import select
  3.  
  4. client1 = socket.socket()
  5. client1.setblocking(False) # 百度创建连接: 非阻塞
  6.  
  7. try:
  8. client1.connect(('www.baidu.com',80))
  9. except BlockingIOError as e:
  10. pass
  11.  
  12. client2 = socket.socket()
  13. client2.setblocking(False) # 百度搜狗连接: 非阻塞
  14. try:
  15. client2.connect(('www.sogou.com',80))
  16. except BlockingIOError as e:
  17. pass
  18.  
  19. client3 = socket.socket()
  20. client3.setblocking(False) # 创建老男孩连接: 非阻塞
  21. try:
  22. client3.connect(('www.oldboyedu.com',80))
  23. except BlockingIOError as e:
  24. pass
  25.  
  26. socket_list = [client1,client2,client3]
  27. conn_list = [client1,client2,client3]
  28.  
  29. while True:
  30. rlist,wlist,elist = select.select(socket_list,conn_list,[],0.005)
  31. # wlist中表示已经连接成功的socket对象
  32. for sk in wlist:
  33. if sk == client1:
  34. sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')
  35. elif sk==client2:
  36. sk.sendall(b'GET /web?query=fdf HTTP/1.0\r\nhost:www.sogou.com\r\n\r\n')
  37. else:
  38. sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.oldboyedu.com\r\n\r\n')
  39. conn_list.remove(sk)
  40. for sk in rlist:
  41. chunk_list = []
  42. while True:
  43. try:
  44. chunk = sk.recv(8096)
  45. if not chunk:
  46. break
  47. chunk_list.append(chunk)
  48. except BlockingIOError as e:
  49. break
  50. body = b''.join(chunk_list)
  51. # print(body.decode('utf-8'))
  52. print('------------>',body)
  53. sk.close()
  54. socket_list.remove(sk)
  55. if not socket_list:
  56. break

单线程并发

  1. import socket
  2. import select
  3.  
  4. class Req(object):
  5. def __init__(self,sk,func):
  6. self.sock = sk
  7. self.func = func
  8.  
  9. def fileno(self):
  10. return self.sock.fileno()
  11.  
  12. class Nb(object):
  13.  
  14. def __init__(self):
  15. self.conn_list = []
  16. self.socket_list = []
  17.  
  18. def add(self,url,func):
  19. client = socket.socket()
  20. client.setblocking(False) # 非阻塞
  21. try:
  22. client.connect((url, 80))
  23. except BlockingIOError as e:
  24. pass
  25. obj = Req(client,func)
  26. self.conn_list.append(obj)
  27. self.socket_list.append(obj)
  28.  
  29. def run(self):
  30.  
  31. while True:
  32. rlist,wlist,elist = select.select(self.socket_list,self.conn_list,[],0.005)
  33. # wlist中表示已经连接成功的req对象
  34. for sk in wlist:
  35. # 发生变换的req对象
  36. sk.sock.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')
  37. self.conn_list.remove(sk)
  38. for sk in rlist:
  39. chunk_list = []
  40. while True:
  41. try:
  42. chunk = sk.sock.recv(8096)
  43. if not chunk:
  44. break
  45. chunk_list.append(chunk)
  46. except BlockingIOError as e:
  47. break
  48. body = b''.join(chunk_list)
  49. # print(body.decode('utf-8'))
  50. sk.func(body)
  51. sk.sock.close()
  52. self.socket_list.remove(sk)
  53. if not self.socket_list:
  54. break
  55.  
  56. def baidu_repsonse(body):
  57. print('百度下载结果:',body)
  58.  
  59. def sogou_repsonse(body):
  60. print('搜狗下载结果:', body)
  61.  
  62. def oldboyedu_repsonse(body):
  63. print('老男孩下载结果:', body)
  64.  
  65. t1 = Nb()
  66. t1.add('www.baidu.com',baidu_repsonse)
  67. t1.add('www.sogou.com',sogou_repsonse)
  68. t1.add('www.oldboyedu.com',oldboyedu_repsonse)
  69. t1.run()

单线程并发高级版

  (三)总结

  1、socket默认是阻塞的,阻塞体现在connect和recv两个阶段

  2、如何让socket编程非阻塞?

  设置setblocking(False)

  3、提高并发方案:

  1. - 多进程
    - 多线程
    - 异步非阻塞模块(Twisted scrapy框架(单线程完成并发)
  1. 4 什么是异步非阻塞?
    - 非阻塞,不等待。
    比如创建socket对某个地址进行connect、获取接收数据recv时默认都会等待(连接成功或接收到数据),才执行后续操作。
    如果设置setblocking(False),以上两个过程就不再等待,但是会报BlockingIOError的错误,只要捕获即可。
    - 异步,通知,执行完成之后自动执行回调函数或自动执行某些操作(通知)。
    比如做爬虫中向某个地址baidu.com发送请求,当请求执行完成之后自执行回调函数。
      5、什么是同步阻塞?
  1. - 阻塞:等
    - 同步:按照顺序逐步执行
     
  2.  
  3.  6.什么是并行和并发?
  1.   并发 不能利用多核,同一时间段内,有多个任务在一个CPU
      并行 能利用多核,同一时刻有多个任务在CPU上同时执行轮流被执行
  1.  

python 线程、进程与协程的更多相关文章

  1. Python 线程&进程与协程

    Python 的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承.Py ...

  2. 多任务-python实现-进程,协程,线程总结(2.1.16)

    @ 目录 1.类比 2.总结 关于作者 1.类比 一个生产玩具的工厂: 一个生产线成为一个进程,一个生产线有多个工人,所以工人为线程 单进程-多线程:一条生产线,多个工人 多进程-多线程:多条生产线, ...

  3. Python之线程、进程和协程

    python之线程.进程和协程 目录: 引言 一.线程 1.1 普通的多线程 1.2 自定义线程类 1.3 线程锁 1.3.1 未使用锁 1.3.2 普通锁Lock和RLock 1.3.3 信号量(S ...

  4. python成长之路 :线程、进程和协程

    python线程 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分 ...

  5. Python之路【第七篇】:线程、进程和协程

    Python之路[第七篇]:线程.进程和协程   Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 1 ...

  6. python运维开发(十一)----线程、进程、协程

    内容目录: 线程 基本使用 线程锁 自定义线程池 进程 基本使用 进程锁 进程数据共享 进程池 协程 线程 线程使用的两种方式,一种为我们直接调用thread模块上的方法,另一种我们自定义方式 方式一 ...

  7. Python 线程和进程和协程总结

    Python 线程和进程和协程总结 线程和进程和协程 进程 进程是程序执行时的一个实例,是担当分配系统资源(CPU时间.内存等)的基本单位: 进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其 ...

  8. python 线程 进程 协程 学习

    转载自大神博客:http://www.cnblogs.com/aylin/p/5601969.html 仅供学习使用···· python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和 ...

  9. python并发编程之Queue线程、进程、协程通信(五)

    单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...

  10. Python菜鸟之路:Python基础-线程、进程、协程

    上节内容,简单的介绍了线程和进程,并且介绍了Python中的GIL机制.本节详细介绍线程.进程以及协程的概念及实现. 线程 基本使用 方法1: 创建一个threading.Thread对象,在它的初始 ...

随机推荐

  1. Spring Boot认证:整合Jwt

    背景 Jwt全称是:json web token.它将用户信息加密到token里,服务器不保存任何用户信息.服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证. 优点 简洁: 可以通过 ...

  2. 正睿国庆DAY2动态规划专题

    正睿国庆DAY2动态规划专题 排列-例题 1~n 的排列个数,每个数要么比旁边两个大,要么比旁边两个小 \(f[i][j]\) 填了前i个数,未填的数有\(j\)个比第\(i\)个小,是波峰 \(g[ ...

  3. [UWP] 自定义一个ItemsPanel

    在做游民星空的搜索页面的时候,需要展示搜索热点词,返回的是一个string数组的形式,然后以一种错落的方式显示,每一个Item的大小都和热点词长度一致,然后一行放不下之后就换行,描述的不太直观,直接看 ...

  4. 浅谈个人对客户端JavaScript同步、异步、执行顺序等概念的理解

    一.同步和异步的概念. 同步:即按代码的顺序执行任务. 在下列代码中,按照同步概念,则是先打印1后打印2. console.log(1); console.log(2); 异步:即执行一个任务的同时执 ...

  5. TCP/UDP的小事情

    UDP: 没有复杂的控制机制,面向无连接的通信服务. 常用于: 包总量少的通信 音视频传输(即时通信) TCP: 对传输.发送.通信.进行控制的协议.面向有连接的协议,只有在确认通信对端存在时才会发送 ...

  6. requests模块(代理)篇

    - 用户验证 - 代理验证 #可能需要使用HTTP basic Auth, 可以这样 # 格式为 用户名:密码@代理地址:端口地址 proxy = { "http": " ...

  7. Java序列化总结(最全)

    概念 实现 Serializable 接口, 它只是一个标记接口,不实现也能够进行序列化 RMI: 远程方法调用 RPC: 远程过程调用 序列化ID 解决了序列化与反序列出现代码不一致的问题, 不一致 ...

  8. ASP.NET Core API ——Dapper的使用

    ASP.NET Core API ——Dapper的使用 简介:Dapper是一个ORM框架,负责数据库和程序语言之间的映射. 使用步骤: l  创建一个IDBConnection的接口对象 l  编 ...

  9. jquery 获取input的值

    $("input").attr("value")   --  获取的是input的默认值 $("input").val()         ...

  10. [CF85E] Guard Towers - 二分+二分图

    题目描述 In a far away kingdom lives a very greedy king. To defend his land, he built n n n guard towers ...