在python 进程、线程 (一)中简单的说过,CPython中的GIL使得同一时刻只能有一个线程运行,即并发执行。并且即使是多核CPU,GIL使得同一个进程中的多个线程也无法映射到多个CPU上运行,这么做最初是为了安全着想,慢慢的也成为了限制CPython性能的问题。
就像是一个线程想要执行,就必须得到GIL,否则就不能拿到CPU资源。但是也不是说一个线程在拿到CPU资源后就一劳永逸,在执行的过程中GIL可能会释放并被其他线程获取,所以说其它的线程会与本线程竞争CPU资源。
在understand GIL:http://www.dabeaz.com/python/UnderstandingGIL.pdf中有关于GIL释放和GIL的概要。
多线程在python2中:当一个线程进行I/O的时候会释放锁,另外当ticks计数达到100(ticks可以看作是Python自身的一个计数器,也可对比着字节码指令理解,专门做用于GIL,每次释放后归零,这个计数可以通过 sys.setcheckinterval 来调整)。锁释放之后,就涉及到线程的调度,线程的锁进行,线程的切换。这是会消耗CPU资源,因此会造成程序性能问题和等待时延。特别是在CPU密集型代码时。
但是对于多进程,GIL就无法限制,多个进程可以再多个CPU上运行,充分利用多核优势。事情往往是相对的,虽然可以充分利用多核优势,但是进程之间的切换却比线程的切换代价更高。
所以选择多线程还是多进程,主要还是看怎样权衡代价,什么样的情况。
1、CPU密集代码
下面来利用斐波那契数列模拟CPU密集运算。
def fib(n):
# 求斐波那契数列的第n个值
if n<=2:
return 1
return fib(n-1)+fib(n-2)
<1>、多进程
打印第25到35个斐波那契数,并计算程序运行时间
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from concurrent.futures import ProcessPoolExecutor
def fib(n):
if n<=2:
return 1
return fib(n-1)+fib(n-2)
if __name__ == "__main__":
with ProcessPoolExecutor(3) as executor: # 使用进程池控制 每次执行3个进程
all_task = [executor.submit(fib, (num)) for num in range(25,35)]
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))
# 输出
exe result: 75025
exe result: 121393
exe result: 196418
exe result: 317811
exe result: 514229
exe result: 832040
exe result: 1346269
exe result: 2178309
exe result: 3524578
exe result: 5702887
last time is: 4.457437038421631
输出结果,每次打印三个exe result,总重打印十个结果,多进程运行时间为4.45秒
<2>、多线程
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from concurrent.futures import ProcessPoolExecutor
def fib(n):
if n<=2:
return 1
return fib(n-1)+fib(n-2)
if __name__ == "__main__":
with ThreadPoolExecutor(3) as executor: # 使用线程池控制 每次执行3个线程
all_task = [executor.submit(fib, (num)) for num in range(25,35)]
start_time = time.time()
for future in as_completed(all_task):
data = future.result()
print("exe result: {www.gcyl152.com/ }".format(data))
print("last time is: {}".format(time.time()-start_time))
# 输出
exe result: 121393
exe result: 75025
exe result: 196418
exe result: 317811
exe result: 514229
exe result: 832040
exe result: 1346269
exe result: 2178309
exe result: 3524578
exe result: 5702887
last time is: 7.3467772006988525
最终程序运行时间为7.34秒
程序的执行之间与计算机的性能有关,每天计算机的执行时间都会有差异。从上述结果中看显然多线程比多进程要耗费时间。这就是因为对于密集代码(密集运算,循环语句等),tick计数很快达到100,GIL来回的释放竞争,线程之间频繁切换,所以对于密集代码的执行中,多线程性能不如对进程。
第一步导入依赖
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'cn.bingoogolapple:bga-banner:2.2.4@aar'
创建BaseService
import java.util.Map;
import io.reactivex.Observable;
import okhttp3.ResponseBody;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.QueryMap;
import retrofit2.http.Url;
public interface BaseService {
@GET
Observable<ResponseBody> get(@Url String url, @QueryMap Map<String, String> map);
@POST
Observable<ResponseBody>www.gcyL157.com post(@Url www.michenggw.com String url, @QueryMap Map<String, String> map);
工具类
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import io.reactivex.Observer;
import io.reactivex.www.yigouyule2.cn android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
public class HttpHelper11 www.mhylpt.com{
private BaseService mBaseService;
public HttpHelper11(){
Retrofit retrofit=new Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl("http://www.zhaoapi.cn/")
.build();
mBaseService=retrofit.create(BaseService.class);
}
//get请求
public HttpHelper11 get(String url, Map<String,String> map){
if(map==null){
map=new HashMap<>();
}
mBaseService.get(url,map)
.subscribeOn(Schedulers.io(www.mcyllpt.com/))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
return this;
}
//post请求
public HttpHelper11 post(String url, Map<String,String> map){
if(map==null){
map=new HashMap<www.dfgjyl.cn>();
}
mBaseService.post(url,map)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
return this;
}
private Observer observer=new Observer<ResponseBody>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseBody responseBody) {
try {
String data= responseBody.string();
listener.success(data);
} catch (IOException e) {
e.printStackTrace(www.365soke.com);
}
}
@Override
public void onError(Throwable e) {
String error= e.getMessage();
listener.fail(error);
}
@Override
public void onComplete() {
}
};
private HttpListener listener;
public void result(HttpListener listener){
this.listener=listener;
}
public interface HttpListener {
void success(String data);
void fail(String error);
}
}
相关文章
- 【Redis-缓存工具类:缓存穿透,缓存击穿,缓存雪崩】
- JAVA学习笔记——Array工具类以及基本类型包装类
- 03_06_JavaWeb||day05_JDBC基础【重点掌握】||day05_1_JDBC基础【重点掌握第五点和会使用JDBCUtils工具类,了解JDBC事务处理位置即可】
- 【Java学习笔记之十二】Java8增强的工具类:Arrays的用法整理总结
- Java 让工具类不可实例化
- Java集合框架:Collections工具类
- 黑马程序员----Java集合框架学习笔记2 Map-工具类-泛型
- 集合框架的工具类----Collections
- 黑马程序员-----Java基础-----集合工具类,jdk1.5新特性,其他对象
- Collections工具类(集合框架)