Python3 与 C# 并发编程之~ 线程篇1

2.线程篇

示例代码:https://github.com/lotapp/BaseCode/tree/master/python/5.concurrent/Thread

终于说道线程了,心酸啊,进程还有点东西下次接着聊,这周4天外出,所以注定发文少了 +_+

用过Java或者Net的重点都在线程这块,Python的重点其实在上篇,但线程自有其独到之处~比如资源共享(更轻量级)

这次采用循序渐进的方式讲解, 先使用,再深入,然后扩展,最后来个案例,呃.呃.呃.先这样计划~欢迎纠正错误

2.1.入门篇

官方文档:https://docs.python.org/3/library/threading.html

进程是由若干线程组成的(一个进程至少有一个线程)

2.1.1.线程案例

用法和 Process差不多,咱先看个案例: Thread(target=test,args=(i,))

import osfrom threading import Thread, current_thread def test(name):    # current_thread()返回当前线程的实例    thread_name = current_thread().name  # 获取线程名    print(f"[编号:{name}],ThreadName:{thread_name}\nPID:{os.getpid()},PPID:{os.getppid()}")def main():    t_list = [Thread(target=test, args=(i, )) for i in range(5)]    for t in t_list:        t.start() # 批量启动    for t in t_list:        t.join() # 批量回收    # 主线程    print(f"[Main]ThreadName:{current_thread().name}\nPID:{os.getpid()},PPID:{os.getppid()}")if __name__ == '__main__':    main()

输出:(同一个进程ID)

[编号:0],ThreadName:Thread-1PID:20533,PPID:19830[编号:1],ThreadName:Thread-2PID:20533,PPID:19830[编号:2],ThreadName:Thread-3PID:20533,PPID:19830[编号:3],ThreadName:Thread-4PID:20533,PPID:19830[编号:4],ThreadName:Thread-5PID:20533,PPID:19830[Main]ThreadName:MainThreadPID:22636,PPID:19830

注意一点:Python里面的线程是Posix Thread

2.1.2.指定线程名

如果想给线程设置一个Div的名字呢?:

from threading import Thread, current_threaddef test():    # current_thread()返回当前线程的实例    print(f"ThreadName:{current_thread().name}")def main():    t1 = Thread(target=test, name="小明")    t2 = Thread(target=test)    t1.start()    t2.start()    t1.join()    t2.join()    # 主线程    print(f"[Main],ThreadName:{current_thread().name}")if __name__ == '__main__':    main()

输出:(你指定有特点的名字,没指定就使用默认命令【联想古时候奴隶名字都是编号,主人赐名就有名了】)

ThreadName:小明ThreadName:Thread-1[Main],ThreadName:MainThread

类的方式创建线程

from threading import Threadclass MyThread(Thread):    def __init__(self, name):        # 设个坑,你可以自行研究下        super().__init__()  # 放在后面就报错了        self.name = name    def run(self):        print(self.name)def main():    t = MyThread(name="小明")    t.start()    t.join()if __name__ == '__main__':    main()

输出:(和Thread初始化的name冲突了【变量名得注意哦】)

小明

2.1.3.线程池案例

from multiprocessing.dummy import Pool as ThreadPool, current_processdef test(i):    # 本质调用了:threading.current_thread    print(f"[编号{i}]{current_process().name}")def main():    p = ThreadPool()    for i in range(5):        p.apply_async(test, args=(i, ))    p.close()    p.join()    print(f"{current_process().name}")if __name__ == '__main__':    main()

输出:

[编号0]Thread-3[编号1]Thread-4[编号3]Thread-2[编号2]Thread-1[编号4]Thread-3MainThread

微微扩展一下

对上面代码,项目里面一般都会这么优化:(并行这块线程后面会讲,不急)

from multiprocessing.dummy import Pool as ThreadPool, current_processdef test(i):    # 源码:current_process = threading.current_thread    print(f"[编号{i}]{current_process().name}")def main():    p = ThreadPool()    p.map_async(test, list(range(5)))    p.close()    p.join()    print(f"{current_process().name}")if __name__ == '__main__':    main()

输出:

[编号0]Thread-2[编号1]Thread-4[编号2]Thread-3[编号4]Thread-2[编号3]Thread-1MainThread

代码改动很小(循环换成了map)性能提升很明显(密集型操作)

2.1.4.其他扩展

Thread初始化参数:

  1. daemon:是否为后台线程(主进程退出后台线程就退出了)

Thread实例对象的方法:

  1. isAlive(): 返回线程是否活动的
  2. getName(): 返回线程名
  3. setName(): 设置线程名
  4. isDaemon():是否为后台线程
  5. setDaemon():设置后台线程

threading模块提供的一些方法:

  1. threading.currentThread(): 返回当前的线程实例
  2. threading.enumerate(): 返回一个包含正在运行的线程List(线程启动后、结束前)
  3. threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果

看一个小案例:

import timefrom threading import Thread, active_countdef test1():    print("test1")    time.sleep(1)    print("test1 ok")def test2():    print("test2")    time.sleep(2)    print("test2 ok")def main():    t1 = Thread(target=test1)    t2 = Thread(target=test2, daemon=True)    t1.start()    t2.start()    t1.join()    print(active_count())    print(t1.is_alive)    print(t2.is_alive)    # t2.join() # 除非加这一句才等daemon线程,不然直接不管了if __name__ == '__main__':    main()

下次就以 multiprocessing.dummy模块为例了,API和 threading几乎一样,进行了一些并发的封装,性价比更高

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术博客

Asp.Net Web API 2第十二课——Media Formatters媒体格式化器

阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.h...

9630
来自专栏Java成神之路

jdom学习读取XML文件

用JDOM读取XML文件需先用org.jdom.input.SAXBuilder对象的build()方法创建Document对象,然后用Document类、El...

10930
来自专栏小灰灰

Java并发学习之CountDownLatch实现原理及使用姿势

CountDownLatch实现原理及使用姿势 在并发编程的场景中,最常见的一个case是某个任务的执行,需要等到多个线程都执行完毕之后才可以进行,Count...

7.7K110
来自专栏云瓣

Node.js 异步异闻录

提到 Node.js, 我们脑海就会浮现异步、非阻塞、单线程等关键词,进一步我们还会想到 buffer、模块机制、事件循环、进程、V8、libuv 等知识点。本...

42680
来自专栏游戏杂谈

Node.js文件编码格式的转换

项目很多 lua 文件不是 utf-8格式,使用 EditPlus 查看的时候,显示为ASCII。还有的是带BOM的,带BOM倒好处理,之前写过,有一定规律。

24540
来自专栏开源优测

[接口测试 - 基础篇] 09 其实吧,读写csv格式也是要掌握的

什么是csv格式 逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表...

32150
来自专栏我有一个梦想

InstallShield 脚本语言学习笔记

InstallShield脚本语言是类似C语言,利用InstallShield的向导或模板都可以生成基本的脚本程序框架,可以在此基础上按自己的意愿进行修改和添加...

23150
来自专栏noteless

ServletRequest HttpServletRequest 请求方法 获取请求参数 请求转发 请求包含 请求转发与重定向区别 获取请求头字段

实际为   HttpServletRequest  或者  ServletRequest,   两者都为接口

25250
来自专栏公众号_薛勤的博客

Java多线程编程核心技术(三)多线程通信

通过本节可以学习到,线程与线程之间不是独立的个体,它们彼此之间可以互相通信和协作。

13880
来自专栏java学习

Java每日一练(2017/7/3)

Java基础 | 数据库 | Android | 学习视频 | 学习资料下载 最新通知 ●回复"每日一练"获取以前的题目! ●【新】Ajax知识点视频更新了!(...

47770

扫码关注云+社区

领取腾讯云代金券