Python高级知识点学习(八)
线程同步 - condition介绍
多线程中的另外一个重要点就是condition:条件变量。
condition是python多线程编程中用于复杂线程间通信的一个锁 叫做条件变量。
cond = threading.Condition() with self.cond: cond.notify() cond.wait()
condition有两层锁, 一把底层锁会在线程调用了wait方法的时候释放, 上面的锁会在每次调用wait的时候分配一把并放入到cond的等待队列中,等到notify方法的唤醒。
有关condition的详情请查阅资料。(这里作者自己暂时还没理清楚原理,见谅)
线程同步 - Semaphore 介绍
信号量,Semaphore。
Semaphore 是用于控制进入数量的锁,控制进入某段代码的线程数。
文件, 读、写, 写一般只是用于一个线程写,读可以允许有多个。
ThreadPoolExecutor线程池
多线程和多进程对比
- 运算,耗cpu的操作,用多进程编程
- 对于io操作来说, 使用多线程编程
由于进程切换代价要高于线程,所以能使用线程就不用进程。
耗费cpu的操作:
def fib(n): if n<=2: return 1 return fib(n-1)+fib(n-2) if __name__ == "__main__": with ThreadPoolExecutor(3) as executor: all_task = [executor.submit(fib, (num)) for num in range(1, 10)] start_time = time.time() for future in as_completed(all_task): data = future.result() print("exe result: {}".format(data)) print("last time is: {}".format(time.time()-start_time))
模拟IO操作:
def random_sleep(n): time.sleep(n) return n if __name__ == "__main__": with ProcessPoolExecutor(3) as executor: all_task = [executor.submit(random_sleep, (num)) for num in [2]*30] start_time = time.time() for future in as_completed(all_task): data = future.result() print("exe result: {}".format(data)) print("last time is: {}".format(time.time()-start_time))
multiprocessing 多进程
使用os.fork
创建子进程,fork只能用于linux/unix中。
import os import time # fork新建子进程 fork只能用于linux/unix中 pid = os.fork() print("a") if pid == 0: print('子进程id:{} ,父进程id是: {}.' .format(os.getpid(), os.getppid())) else: print('我是父进程, 我fork出的子进程id是:{}.'.format(pid)) time.sleep(2) 运行结果: a 我是父进程, 我fork出的子进程id是:3093. a 子进程id:3093 ,父进程id是: 3092.
运行结果中,可以看到打印了两次a,因为在执行完pid = os.fork()
这行代码后,就创建了一个子进程,且子进程把父进程中的数据原样拷贝了一份到自己的进程中,所以父进程中打印一次,子进程中又打印一次。
多进程编程:
import multiprocessing # 多进程编程 import time def get_html(n): time.sleep(n) print("sub_progress success") return n if __name__ == "__main__": progress = multiprocessing.Process(target=get_html, args=(2,)) print(progress.pid) progress.start() print(progress.pid) progress.join() print("main progress end")
使用进程池:
import multiprocessing # 多进程编程 import time def get_html(n): time.sleep(n) print("sub_progress success") return n if __name__ == "__main__": # 使用进程池 pool = multiprocessing.Pool(multiprocessing.cpu_count()) result = pool.apply_async(get_html, args=(3,)) # 等待所有任务完成 pool.close() pool.join() print(result.get())
进程池另一种方法:
import multiprocessing # 多进程编程 import time def get_html(n): time.sleep(n) print("sub_progress success") return n if __name__ == "__main__": # 使用进程池 pool = multiprocessing.Pool(multiprocessing.cpu_count()) for result in pool.imap_unordered(get_html, [1, 5, 3]): print("{} sleep success".format(result))
进程间通信 Queue、Pipe,Manager
共享全局变量不能适用于多进程编程,可以适用于多线程。
进程间通信和线程间通信有相同也有不同,不同点是之前在多线程中用的线程间通信的类和线程间同步的锁在多进程中是不能用的。
使用multiprocessing中的Queue实现进程通信
import time from multiprocessing import Process, Queue, Pool, Manager, Pipe def producer(queue): queue.put("a") time.sleep(2) def consumer(queue): time.sleep(2) data = queue.get() print(data) if __name__ == "__main__": queue = Queue(10) my_producer = Process(target=producer, args=(queue,)) my_consumer = Process(target=consumer, args=(queue,)) my_producer.start() my_consumer.start() my_producer.join() my_consumer.join()
一定要使用multiprocessing中的Queue
,如果使用import queue
这个queue是不行的。
pool中的进程间通信需要使用manager中的queue
multiprocessing中的queue不能用于pool进程池。
pool中的进程间通信需要使用manager中的queue
def producer(queue): queue.put("a") time.sleep(2) def consumer(queue): time.sleep(2) data = queue.get() print(data) if __name__ == "__main__": queue = Manager().Queue(10) pool = Pool(2) pool.apply_async(producer, args=(queue,)) pool.apply_async(consumer, args=(queue,)) pool.close() pool.join()
使用Manager,多进程修改同一变量:
def add_data(p_dict, key, value): p_dict[key] = value if __name__ == "__main__": progress_dict = Manager().dict() from queue import PriorityQueue first_progress = Process(target=add_data, args=(progress_dict, "a", 22)) second_progress = Process(target=add_data, args=(progress_dict, "b", 23)) first_progress.start() second_progress.start() first_progress.join() second_progress.join() print(progress_dict)
可以看到两个进程对一个dict变量做值得填充,最终主进程中打印出了最终的dict。
通过pipe实现进程间通信:
pipe的性能高于queue。
pipe只能适用于两个进程。
def producer(pipe): pipe.send("a") def consumer(pipe): print(pipe.recv()) if __name__ == "__main__": recevie_pipe, send_pipe = Pipe() #pipe只能适用于两个进程 my_producer = Process(target=producer, args=(send_pipe, )) my_consumer = Process(target=consumer, args=(recevie_pipe,)) my_producer.start() my_consumer.start() my_producer.join() my_consumer.join()
my_producer进程给my_consumer进程发送的a变量可以正常打印。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
什么!Python从入门到放弃?方法不对一切白费!
从你开始学习编程的那一刻起,就注定了以后所要走的路—从编程学习者开始,依次经历实习生、程序员、软件工程师、架构师、CTO等职位的磨砺;当你站在职位顶峰的位置蓦然回首时,会发现自己的成功并不是偶然,在程序员的成长之路上会有不断修改代码、寻找并解决Bug、不停测试程序和修改项目的经历。 不可否认的是,只要你在自己的开发生涯中稳扎稳打,并且善于总结和学习,最终将会得到可喜的收获。 对于一名程序开发初学者来说,究竟如何学习才能提高自己的开发技术呢?答案之一就是买合适的书籍进行学习。但是,市面上许多面向初学者的编程书籍中的大多数篇幅都是基础知识讲解,多偏向于理论,读者读了以后面对实战项目时还是无从下手。 如何实现从理论平滑过渡到项目实战,是初学者迫切需要解决的难题,为此,特意编写了本书。 本书用一本书的容量讲解了入门类、范例类和项目实战类3类图书的知识,并且对实战知识不是点到为止地讲解,而是深入地探讨。用“纸质书+视频和源程序+网络答疑”的方式,实现了“入门+范例演练+项目实战”的完美呈现,帮助读者从入门顺利过渡到适应项目实战的角色。 进入2018年后,身边越来越多的人说Python语言如日...
- 下一篇
Java入门系列-16-继承
这一篇文章教给新手学会使用继承,及理解继承的概念。掌握访问修饰符、掌握 final 关键字的用法。 继承 为什么要使用继承 首先我们先看一下这两个类: public class Teacher { private int teachingAge; private String name; private int age; public void teach() { } public void seyHi() { System.out.println("我是:"+this.name); } } public class Student { private int studentNo; private String name; private int age; public void learn() { } public void seyHi() { System.out.println("我是:"+this.name); } } Student 类和 Teacher 类中有一些相同的属性和方法,这些都属于重复代码,当一个程序中有大量的类时,就会产生大量的重复代码。这些重复的代码能不能抽取...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7设置SWAP分区,小内存服务器的救世主