Python网络编程之线程与进程

What is a Thread?

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位,一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

在同一个进程内的线程的数据是可以进行互相访问的。

线程的切换使用过上下文来实现的,比如有一本书,有a和b这两个人(两个线程)看,a看完之后记录当前看到那一页哪一行,然后交给b看,b看完之后记录当前看到了那一页哪一行,此时a又要看了,那么a就通过上次记录的值(上下文)直接找到上次看到了哪里,然后继续往下看。


What is a Process?

一个进程至少要包含一个线程,每个进程在启动的时候就会自动的启动一个线程,进程里面的第一个线程就是主线程,每次在进程内创建的子线程都是由主线程进程创建和销毁,子线程也可以由主线程创建出来的线程创建和销毁线程。

进程是对各种资源管理的集合,比如要调用内存、CPU、网卡、声卡等,进程要操作上述的硬件之前都必须要创建一个线程,进程里面可以包含多个线程,QQ就是一个进程。

继续拿QQ来说,比如我现在打卡了QQ的聊天窗口、个人信息窗口、设置窗口等,那么每一个打开的窗口都是一个线程,他们都在执行不同的任务,比如聊天窗口这个线程可以和好友进行互动,聊天,视频等,个人信息窗口我可以查看、修改自己的资料。

为了进程安全起见,所以两个进程之间的数据是不能够互相访问的(默认情况下),比如自己写了一个应用程序,然后让别人运行起来,那么我的这个程序就可以访问用户启动的其他应用,我可以通过我自己的程序去访问QQ,然后拿到一些聊天记录等比较隐秘的信息,那么这个时候就不安全了,所以说进程与进程之间的数据是不可以互相访问的,而且每一个进程的内存是独立的。

进程与线程的区别?

  1. 线程是执行的指令集,进程是资源的集合
  2. 线程的启动速度要比进程的启动速度要快
  3. 两个线程的执行速度是一样的
  4. 进程与线程的运行速度是没有可比性的
  5. 线程共享创建它的进程的内存空间,进程的内存是独立的。
  6. 两个线程共享的数据都是同一份数据,两个子进程的数据不是共享的,而且数据是独立的;
  7. 同一个进程的线程之间可以直接交流,同一个主进程的多个子进程之间是不可以进行交流,如果两个进程之间需要通信,就必须要通过一个中间代理来实现;
  8. 一个新的线程很容易被创建,一个新的进程创建需要对父进程进行一次克隆
  9. 一个线程可以控制和操作同一个进程里的其他线程,线程与线程之间没有隶属关系,但是进程只能操作子进程
  10. 改变主线程,有可能会影响到其他线程的行为,但是对于父进程的修改是不会影响子进程;

一个多并发的小脚本

  1. import threading
  2. import time
  3. def Princ(String):
  4. print(‘task‘, String)
  5. time.sleep(5)
  6. # target=目标函数, args=传入的参数
  7. t1 = threading.Thread(target=Princ, args=(‘t1‘,))
  8. t1.start()
  9. t2 = threading.Thread(target=Princ, args=(‘t1‘,))
  10. t2.start()
  11. t3 = threading.Thread(target=Princ, args=(‘t1‘,))
  12. t3.start()

参考文档

进程与线程的一个简单解释
http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
Linux进程与线程的区别
https://my.oschina.net/cnyinlinux/blog/422207

线程

Thread module emulating a subset of Java’s threading model.

调用threading模块调用线程的两种方式

直接调用

  1. import threading
  2. import time
  3. def Princ(String):
  4. print(‘task‘, String)
  5. time.sleep(5)
  6. # target=目标函数, args=传入的参数
  7. t1 = threading.Thread(target=Princ, args=(‘t1‘,))
  8. t1.start()
  9. t2 = threading.Thread(target=Princ, args=(‘t1‘,))
  10. t2.start()
  11. t3 = threading.Thread(target=Princ, args=(‘t1‘,))
  12. t3.start()

通过类调用

  1. import threading
  2. import time
  3. class MyThreading(threading.Thread):
  4. def __init__(self, conn):
  5. super(MyThreading, self).__init__()
  6. self.conn = conn
  7. def run(self):
  8. print(‘run task‘, self.conn)
  9. time.sleep(5)
  10. t1 = MyThreading(‘t1‘)
  11. t2 = MyThreading(‘t2‘)
  12. t1.start()
  13. t2.start()

多线程

多线程在Python内实则就是一个假象,为什么这么说呢,因为CPU的处理速度是很快的,所以我们看起来以一个线程在执行多个任务,每个任务的执行速度是非常之快的,利用上下文切换来快速的切换任务,以至于我们根本感觉不到。

但是频繁的使用上下文切换也是要耗费一定的资源,因为单线程在每次切换任务的时候需要保存当前任务的上下文。

什么时候用到多线程?

首先IO操作是不占用CPU的,只有计算的时候才会占用CPU(譬如1+1=2),Python中的多线程不适合CPU密集型的任务,适合IO密集型的任务(sockt server)。

启动多个线程

主进程在启动之后会启动一个主线程,下面的脚本中让主线程启动了多个子线程,然而启动的子线程是独立的,所以主线程不会等待子线程执行完毕,而是主线程继续往下执行,并行执行。

  1. for i in range(50):
  2. t = threading.Thread(target=Princ, args=(‘t-%s‘ % (i),))
  3. t.start()

join()

join()方法可以让程序等待每一个线程之后完成之后再往下执行,又成为串行执行。

  1. import threading
  2. import time
  3. def Princ(String):
  4. print(‘task‘, String)
  5. time.sleep(1)
  6. for i in range(50):
  7. t = threading.Thread(target=Princ, args=(‘t-%s‘ % (i),))
  8. t.start()
  9. # 当前线程执行完毕之后在执行后面的线程
  10. t.join()

让主线程阻塞,子现在并行执行

  1. import threading
  2. import time
  3. def Princ(String):
  4. print(‘task‘, String)
  5. time.sleep(2)
  6. # 执行子线程的时间
  7. start_time = time.time()
  8. # 存放线程的实例
  9. t_objs = []
  10. for i in range(50):
  11. t = threading.Thread(target=Princ, args=(‘t-%s‘ % (i),))
  12. t.start()
  13. # 为了不让后面的子线程阻塞,把当前的子线程放入到一个列表中
  14. t_objs.append(t)
  15. # 循环所有子线程实例,等待所有子线程执行完毕
  16. for t in t_objs:
  17. t.join()
  18. # 当前时间减去开始时间就等于执行的过程中需要的时间
  19. print(time.time() - start_time)

查看主线程与子线程

  1. import threading
  2. class MyThreading(threading.Thread):
  3. def __init__(self):
  4. super(MyThreading, self).__init__()
  5. def run(self):
  6. print(‘我是子线程: ‘, threading.current_thread())
  7. t = MyThreading()
  8. t.start()
  9. print(‘我是主线程: ‘, threading.current_thread())

输出如下:

  1. C:\Python\Python35\python.exe E:/MyCodeProjects/进程与线程/s3.py
  2. 我是子线程:  <MyThreading(Thread-1, started 7724)>
  3. 我是主线程:  <_MainThread(MainThread, started 3680)>
  4. Process finished with exit code 0

查看当前进程的活动线程个数

  1. import threading
  2. class MyThreading(threading.Thread):
  3. def __init__(self):
  4. super(MyThreading, self).__init__()
  5. def run(self):
  6. print(‘www.anshengme.com‘)
  7. t = MyThreading()
  8. t.start()
  9. print(‘线程个数: ‘, threading.active_count())

输出如下:

  1. C:\Python\Python35\python.exe E:/MyCodeProjects/进程与线程/s3.py
  2. www.anshengme.com
  3. # 一个主线程和一个子线程
  4. 线程个数:  2
  5. Process finished with exit code 0

Event

Event是线程间通信最间的机制之一:一个线程发送一个event信号,其他的线程则等待这个信号。用于主线程控制其他线程的执行。 Events 管理一个flag,这个flag可以使用set
()设置成True或者使用clear()重置为False,wait()则用于阻塞,在flag为True之前。flag默认为False。

选项 描述
Event.wait([timeout]) 堵塞线程,直到Event对象内部标识位被设为True或超时(如果提供了参数timeout)
Event.set() 将标识位设为Ture
Event.clear() 将标识伴设为False
Event.isSet() 判断标识位是否为Ture
  1. #!/use/bin/env python
  2. # _*_ coding: utf-8- _*_
  3. import threading
  4. def runthreading(event):
  5. print("Start...")
  6. event.wait()
  7. print("End...")
  8. event_obj = threading.Event()
  9. for n in range(10):
  10. t = threading.Thread(target=runthreading, args=(event_obj,))
  11. t.start()
  12. event_obj.clear()
  13. inp = input("True/False?>> ")
  14. if inp == "True":
  15. event_obj.set()
  16. `

守护进程(守护线程)

一个主进程可以启动多个守护进程,但是主进程必须要一直运行,如果主进程挂掉了,那么守护进程也会随之挂掉

程序会等待主线程(进程)执行完毕,但是不会等待守护进程(线程)

  1. import threading
  2. import time
  3. def Princ(String):
  4. print(‘task‘, String)
  5. time.sleep(2)
  6. for i in range(50):
  7. t = threading.Thread(target=Princ, args=(‘t-%s‘ % (i),))
  8. t.setDaemon(True)  # 把当前线程设置为守护线程,要在start之前设置
  9. t.start()

场景预设: 比如现在有一个FTP服务,每一个用户连接上去的时候都会创建一个守护线程,现在已经有300个用户连接上去了,就是说已经创建了300个守护线程,但是突然之间FTP服务宕掉了,这个时候就不会等待守护线程执行完毕再退出,而是直接退出,如果是普通的线程,那么就会登台线程执行完毕再退出。

  1. #!/use/bin/env python
  2. # _*_ coding:utf-8 _*_
  3. from multiprocessing import Process
  4. import time
  5. def runprocess(arg):
  6. print(arg)
  7. time.sleep(2)
  8. p = Process(target=runprocess, args=(11,))
  9. p.daemon=True
  10. p.start()
  11. print("end")

线程之间的数据交互与锁(互斥锁)

python2.x需要加锁,但是在python3.x上面就不需要了

  1. # _*_ coding:utf-8 _*_
  2. import threading
  3. def Princ():
  4. # 获取锁
  5. lock.acquire()
  6. # 在函数内可以直接修改全局变量
  7. global number
  8. number += 1
  9. # 为了避免让程序出现串行,不能加sleep
  10. # time.sleep(1)
  11. # 释放锁
  12. lock.release()
  13. # 锁
  14. lock = threading.Lock()
  15. # 主线程的number
  16. number = 0
  17. t_objs = []
  18. for i in range(100):
  19. t = threading.Thread(target=Princ)
  20. t.start()
  21. t_objs.append(t)
  22. for t in t_objs:
  23. t.join()
  24. print(‘Number:‘, number)

递归锁(Lock/RLock)

  1. import threading
  2. def run1():
  3. print("grab the first part data")
  4. lock.acquire()
  5. global num
  6. num += 1
  7. lock.release()
  8. return num
  9. def run2():
  10. print("grab the second part data")
  11. lock.acquire()
  12. global num2
  13. num2 += 1
  14. lock.release()
  15. return num2
  16. def run3():
  17. lock.acquire()
  18. res = run1()
  19. print(‘--------between run1 and run2-----‘)
  20. res2 = run2()
  21. lock.release()
  22. print(res, res2)
  23. t_objs = []
  24. if __name__ == ‘__main__‘:
  25. num, num2 = 0, 0
  26. lock = threading.RLock()  # RLock()类似创建了一个字典,每次退出的时候找到字典的值进行退出
  27. # lock = threading.Lock()  # Lock()会阻塞在这儿
  28. for i in range(10):
  29. t = threading.Thread(target=run3)
  30. t.start()
  31. t_objs.append(t)
  32. for t in t_objs:
  33. t.join()
  34. print(num, num2)

信号量(Semaphore)

互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据

  1. import threading
  2. import time
  3. def run(n):
  4. semaphore.acquire()  # 获取信号,信号可以有多把锁
  5. time.sleep(1)  # 等待一秒钟
  6. print("run the thread: %s\n" % n)
  7. semaphore.release()  # 释放信号
  8. t_objs = []
  9. if __name__ == ‘__main__‘:
  10. semaphore = threading.BoundedSemaphore(5)  # 声明一个信号量,最多允许5个线程同时运行
  11. for i in range(20):  # 运行20个线程
  12. t = threading.Thread(target=run, args=(i,))  # 创建线程
  13. t.start()  # 启动线程
  14. t_objs.append(t)
  15. for t in t_objs:
  16. t.join()
  17. print(‘>>>>>>>>>>>>>‘)

以上代码中,类似与创建了一个队列,最多放5个任务,每执行完成一个任务就会往后面增加一个任务。

多进程

多进程的资源是独立的,不可以互相访问。

启动一个进程

  1. from multiprocessing import Process
  2. import time
  3. def f(name):
  4. time.sleep(2)
  5. print(‘hello‘, name)
  6. if __name__ == ‘__main__‘:
  7. # 创建一个进程
  8. p = Process(target=f, args=(‘bob‘,))
  9. # 启动
  10. p.start()
  11. # 等待进程执行完毕
  12. p.join(

在进程内启动一个线程

  1. from multiprocessing import Process
  2. import threading
  3. def Thread(String):
  4. print(String)
  5. def Proces(String):
  6. print(‘hello‘, String)
  7. t = threading.Thread(target=Thread, args=(‘Thread %s‘ % (String),))  # 创建一个线程
  8. t.start()  # 启动它
  9. if __name__ == ‘__main__‘:
  10. p = Process(target=Proces, args=(‘World‘,))  # 创建一个进程
  11. p.start()  # 启动
  12. p.join()  # 等待进程执行完毕

启动一个多进程

  1. from multiprocessing import Process
  2. import time
  3. def f(name):
  4. time.sleep(2)
  5. print(‘hello‘, name)
  6. if __name__ == ‘__main__‘:
  7. for n in range(10):  # 创建一个进程
  8. p = Process(target=f, args=(‘bob %s‘ % (n),))
  9. # 启动
  10. p.start()
  11. # 等待进程执行完毕

获取启动进程的PID

  1. # _*_ coding:utf-8 _*_
  2. from multiprocessing import Process
  3. import os
  4. def info(String):
  5. print(String)
  6. print(‘module name:‘, __name__)
  7. print(‘父进程的PID:‘, os.getppid())
  8. print(‘子进程的PID:‘, os.getpid())
  9. print("\n")
  10. def ChildProcess():
  11. info(‘\033[31;1mChildProcess\033[0m‘)
  12. if __name__ == ‘__main__‘:
  13. info(‘\033[32;1mTheParentProcess\033[0m‘)
  14. p = Process(target=ChildProcess)
  15. p.start()

输出结果

  1. C:\Python\Python35\python.exe E:/MyCodeProjects/多进程/s1.py
  2. TheParentProcess
  3. module name: __main__
  4. # Pycharm的PID
  5. 父进程的PID: 6888
  6. # 启动的脚本PID
  7. 子进程的PID: 4660
  8. ChildProcess
  9. module name: __mp_main__
  10. # 脚本的PID
  11. 父进程的PID: 4660
  12. # 父进程启动的子进程PID
  13. 子进程的PID: 8452
  14. Process finished with exit code 0

进程间通信

默认情况下进程与进程之间是不可以互相通信的,若要实现互相通信则需要一个中间件,另个进程之间通过中间件来实现通信,下面是进程间通信的几种方式。

进程Queue

  1. # _*_ coding:utf-8 _*_
  2. from multiprocessing import Process, Queue
  3. def ChildProcess(Q):
  4. Q.put([‘Hello‘, None, ‘World‘])  # 在Queue里面上传一个列表
  5. if __name__ == ‘__main__‘:
  6. q = Queue()  # 创建一个Queue
  7. p = Process(target=ChildProcess, args=(q,))  # 创建一个子进程,并把Queue传给子进程,相当于克隆了一份Queue
  8. p.start()  # 启动子进程
  9. print(q.get())  # 获取q中的数据
  10. p.join()

管道(Pipes)

  1. # _*_ coding:utf-8 _*_
  2. from multiprocessing import Process, Pipe
  3. def ChildProcess(conn):
  4. conn.send([‘Hello‘, None, ‘World‘])  # 写一段数据
  5. conn.close()  # 关闭
  6. if __name__ == ‘__main__‘:
  7. parent_conn, child_conn = Pipe()  # 生成一个管道实例,parent_conn, child_conn管道的两头
  8. p = Process(target=ChildProcess, args=(child_conn,))
  9. p.start()
  10. print(parent_conn.recv())  # 收取消息
  11. p.join()

数据共享(Managers)

  1. # _*_ coding:utf-8 _*_
  2. # _*_ coding:utf-8 _*_
  3. from multiprocessing import Process, Manager
  4. import os
  5. def ChildProcess(Dict, List):
  6. Dict[‘k1‘] = ‘v1‘
  7. Dict[‘k2‘] = ‘v2‘
  8. List.append(os.getpid())  # 获取子进程的PID
  9. print(List)  # 输出列表中的内容
  10. if __name__ == ‘__main__‘:
  11. manager = Manager()  # 生成Manager对象
  12. Dict = manager.dict()  # 生成一个可以在多个进程之间传递共享的字典
  13. List = manager.list()  # 生成一个字典
  14. ProcessList = []  # 创建一个空列表,存放进程的对象,等待子进程执行用于
  15. for i in range(10):  # 生成是个子进程
  16. p = Process(target=ChildProcess, args=(Dict, List))  # 创建一个子进程
  17. p.start()  # 启动
  18. ProcessList.append(p)  # 把子进程添加到p_list列表中
  19. for res in ProcessList:  # 循环所有的子进程
  20. res.join()  # 等待执行完毕
  21. print(‘\n‘)
  22. print(Dict)
  23. print(List)

输出结果

  1. C:\Python\Python35\python.exe E:/MyCodeProjects/多进程/s4.py
  2. [5112]
  3. [5112, 3448]
  4. [5112, 3448, 4584]
  5. [5112, 3448, 4584, 2128]
  6. [5112, 3448, 4584, 2128, 11124]
  7. [5112, 3448, 4584, 2128, 11124, 10628]
  8. [5112, 3448, 4584, 2128, 11124, 10628, 5512]
  9. [5112, 3448, 4584, 2128, 11124, 10628, 5512, 10460]
  10. [5112, 3448, 4584, 2128, 11124, 10628, 5512, 10460, 10484]
  11. [5112, 3448, 4584, 2128, 11124, 10628, 5512, 10460, 10484, 6804]
  12. {‘k1‘: ‘v1‘, ‘k2‘: ‘v2‘}
  13. [5112, 3448, 4584, 2128, 11124, 10628, 5512, 10460, 10484, 6804]
  14. Process finished with exit code 0

锁(Lock)

  1. from multiprocessing import Process, Lock
  2. def ChildProcess(l, i):
  3. l.acquire()  # 获取锁
  4. print(‘hello world‘, i)
  5. l.release()  # 释放锁
  6. if __name__ == ‘__main__‘:
  7. lock = Lock()  # 生成Lock对象
  8. for num in range(10):
  9. Process(target=ChildProcess, args=(lock, num)).start()  # 创建并启动一个子进程

进程池

同一时间启动多少个进程

  1. #!/use/bin/env python
  2. # _*_ coding: utf-8 _*_
  3. from multiprocessing import Pool
  4. import time
  5. def myFun(i):
  6. time.sleep(2)
  7. return i+100
  8. def end_call(arg):
  9. print("end_call>>", arg)
  10. p = Pool(5)  # 允许进程池内同时放入5个进程
  11. for i in range(10):
  12. p.apply_async(func=myFun, args=(i,),callback=end_call) # # 平行执行,callback是主进程来调用
  13. # p.apply(func=Foo)  # 串行执行
  14. print("end")
  15. p.close()
  16. p.join() # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。

线程池

简单实现

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import threading
  4. import queue
  5. import time
  6. class MyThread:
  7. def __init__(self,max_num=10):
  8. self.queue = queue.Queue()
  9. for n in range(max_num):
  10. self.queue.put(threading.Thread)
  11. def get_thread(self):
  12. return self.queue.get()
  13. def put_thread(self):
  14. self.queue.put(threading.Thread)
  15. pool = MyThread(5)
  16. def RunThread(arg,pool):
  17. print(arg)
  18. time.sleep(2)
  19. pool.put_thread()
  20. for n in range(30):
  21. thread = pool.get_thread()
  22. t = thread(target=RunThread, args=(n,pool,))
  23. t.start()

复杂版本

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import queue
  4. import threading
  5. import contextlib
  6. import time
  7. StopEvent = object()
  8. class ThreadPool(object):
  9. def __init__(self, max_num, max_task_num = None):
  10. if max_task_num:
  11. self.q = queue.Queue(max_task_num)
  12. else:
  13. self.q = queue.Queue()
  14. self.max_num = max_num
  15. self.cancel = False
  16. self.terminal = False
  17. self.generate_list = []
  18. self.free_list = []
  19. def run(self, func, args, callback=None):
  20. """
  21. 线程池执行一个任务
  22. :param func: 任务函数
  23. :param args: 任务函数所需参数
  24. :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)
  25. :return: 如果线程池已经终止,则返回True否则None
  26. """
  27. if self.cancel:
  28. return
  29. if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
  30. self.generate_thread()
  31. w = (func, args, callback,)
  32. self.q.put(w)
  33. def generate_thread(self):
  34. """
  35. 创建一个线程
  36. """
  37. t = threading.Thread(target=self.call)
  38. t.start()
  39. def call(self):
  40. """
  41. 循环去获取任务函数并执行任务函数
  42. """
  43. current_thread = threading.currentThread()
  44. self.generate_list.append(current_thread)
  45. event = self.q.get()
  46. while event != StopEvent:
  47. func, arguments, callback = event
  48. try:
  49. result = func(*arguments)
  50. success = True
  51. except Exception as e:
  52. success = False
  53. result = None
  54. if callback is not None:
  55. try:
  56. callback(success, result)
  57. except Exception as e:
  58. pass
  59. with self.worker_state(self.free_list, current_thread):
  60. if self.terminal:
  61. event = StopEvent
  62. else:
  63. event = self.q.get()
  64. else:
  65. self.generate_list.remove(current_thread)
  66. def close(self):
  67. """
  68. 执行完所有的任务后,所有线程停止
  69. """
  70. self.cancel = True
  71. full_size = len(self.generate_list)
  72. while full_size:
  73. self.q.put(StopEvent)
  74. full_size -= 1
  75. def terminate(self):
  76. """
  77. 无论是否还有任务,终止线程
  78. """
  79. self.terminal = True
  80. while self.generate_list:
  81. self.q.put(StopEvent)
  82. self.q.queue.clear()
  83. @contextlib.contextmanager
  84. def worker_state(self, state_list, worker_thread):
  85. """
  86. 用于记录线程中正在等待的线程数
  87. """
  88. state_list.append(worker_thread)
  89. try:
  90. yield
  91. finally:
  92. state_list.remove(worker_thread)
  93. # How to use
  94. pool = ThreadPool(5)
  95. def callback(status, result):
  96. # status, execute action status
  97. # result, execute action return value
  98. pass
  99. def action(i):
  100. print(i)
  101. for i in range(30):
  102. ret = pool.run(action, (i,), callback)
  103. time.sleep(5)
  104. print(len(pool.generate_list), len(pool.free_list))
  105. print(len(pool.generate_list), len(pool.free_list))
  106. pool.close()
  107. pool.terminate()

什么是IO密集型和CPU密集型?

IO密集型(I/O bound)

频繁网络传输、读取硬盘及其他IO设备称之为IO密集型,最简单的就是硬盘存取数据,IO操作并不会涉及到CPU。

计算密集型(CPU bound)

程序大部分在做计算、逻辑判断、循环导致cpu占用率很高的情况,称之为计算密集型,比如说python程序中执行了一段代码1+1,这就是在计算1+1的值

时间: 2024-10-09 03:51:54

Python网络编程之线程与进程的相关文章

python网络编程基础(线程与进程、并行与并发、同步与异步)

python网络编程基础(线程与进程.并行与并发.同步与异步) 目录 线程与进程 并行与并发 同步与异步 线程与进程 进程 前言 进程的出现是为了更好的利用CPU资源使到并发成为可能. 假设有两个任务A和B,当A遇到IO操作,CPU默默的等待任务A读取完操作再去执行任务B,这样无疑是对CPU资源的极大的浪费.聪明的老大们就在想若在任务A读取数据时,让任务B执行,当任务A读取完数据后,再切换到任务A执行.注意关键字切换,自然是切换,那么这就涉及到了状态的保存,状态的恢复,加上任务A与任务B所需要的

Python——网络编程(三) 进程与线程

1. 一个程序至少有一个进程,一个进程至少有一个线程(进程可以理解成线程的容器). 2. 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率. 线程在执行过程中与进程还是有区别的.每个独立的线程有一个程序运行的入口.顺序执行序列和程序的出口. 但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制. 3. 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调 度的一个独立单位,是分配资源的基本单位,也是

Python并发编程之线程池/进程池--concurrent.futures模块

h2 { color: #fff; background-color: #f7af0d; padding: 3px; margin: 10px 0px } 一.关于concurrent.futures模块 Python标准库为我们提供了threading和multiprocessing模块编写相应的多线程/多进程代码,但是当项目达到一定的规模,频繁创建/销毁进程或者线程是非常消耗资源的,这个时候我们就要编写自己的线程池/进程池,以空间换时间.但从Python3.2开始,标准库为我们提供了conc

python网络编程--管道,信号量,Event,进程池,回调函数

1.管道 加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行任务修改,即串行修改,速度慢了,但牺牲了速度却保证了数据安全. 文件共享数据实现进程间的通信,但问题是: 1.效率低(共享数据基于文件,而文件是硬盘上的数据) 2.需要自己加锁处理 而使用multiprocess模块为我们提供的基于消息IPC通信机制:通信和管道 可以帮我们解决这两个问题. 队列和管道都是将数据存放于内存内,而队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来来,因而队列才是进程间通信的

[Python网络编程]浅析守护进程后台任务的设计与实现

在做基于B/S应用中,经常有需要后台运行任务的需求,最简单比如发送邮件.在一些如防火墙,WAF等项目中,前台只是为了展示内容与各种参数配置,后台守护进程才是重头戏.所以在防火墙配置页面中可能会经常看到调用cgi,但真正做事的一般并不是cgi,比如说执行关机命令,他们的逻辑如下: (ps:上图所说的前台界面包含通常web开发中的后端,不然也没有socket一说) 为什么要这么设计 你可能疑惑为什么要这么设计,我觉得理由如下: 首先有一点说明,像防火墙等基本上都运行在类Linux平台上 1.安全问题

[python] 网络编程之套接字Socket、TCP和UDP通信实例

很早以前研究过C#和C++的网络通信,参考我的文章: C#网络编程之Tcp实现客户端和服务器聊天 C#网络编程之套接字编程基础知识 C#网络编程之使用Socket类Send.Receive方法的同步通讯 Python网络编程也类似.同时最近找工作笔试面试考察Socket套接字.TCP\UDP区别比较多,所以这篇文章主要精简了<Python核心编程(第二版)>第16章内容.内容包括:服务器和客户端架构.套接字Socket.TCP\UDP通信实例和常见笔试考题. 最后希望文章对你有所帮助,如果有不

Python 网络编程(二)

Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单的仿ssh的socket程序,实现的功能为客户端发送命令,服务端接收到客户端的命令,然后在服务器上通过subrocess模块执行命令,如果命令执行有误,输出内容为空,则返回"command error"的语句给客户端,否则将命令执行的结果返回给客户端 服务端 1 2 3 4 5 6 7 8

大数据技术之_16_Scala学习_11_客户信息管理系统+并发编程模型 Akka+Akka 网络编程-小黄鸡客服案例+Akka 网络编程-Spark Master Worker 进程通讯项目

第十五章 客户信息管理系统15.1 项目的开发流程15.2 项目的需求分析15.3 项目的界面15.4 项目的设计-程序框架图15.5 项目的功能实现15.5.1 完成 Customer 类15.5.2 完成显示主菜单和退出软件功能15.5.3 完成显示客户列表的功能15.5.4 完成添加客户的功能15.5.5 完成删除客户的功能15.5.6 完善退出确认功能15.5.7 完善删除确认功能15.5.8 完成修改客户的功能第十六章 并发编程模型 Akka16.1 Akka 的介绍16.2 Acto

python 网络编程 (二)---tcp

异常 python的socket模块实际上定义了4种可能出现的异常: 1)与一般I/O 和通信问题有关的socket.error; 2)与查询地址信息有关的socket.gaierror; 3)与其他地址错误有关的socket.herror; 4)与在一个socket上调用settimeout()后,处理超时有关的socket.timeout; import socket, sys, time host = sys.argv[1] textport = sys.argv[2] filename