`
leadyu
  • 浏览: 52344 次
  • 性别: Icon_minigender_1
  • 来自: 广州,福州
文章分类
社区版块
存档分类
最新评论

Jwebap项目(四)——性能监控工具Jwebap: 0.5.8版本发布

阅读更多
一直想写一篇关于Jwebap(jwebap.sourceforge.net)项目的介绍文章,鉴于0.5.8版本的发布,我整理了下发表出来,希望大家感兴趣。

引用
背景
最初,在06年底由于要帮助几个大型项目进行性能上的优化,有了开发一个专用于profiling组件的想法,于是有了Jwebap,慢慢的到了07年6月份开始有了最初的方案,在11月终于在sourceforge上发布了第一个版本。

Jwebap能带来什么?
Jwebap是一个用于J2EE工程(EJB以及WebModule系统)进行性能监控的组件,它有几个特点:

1)基于ASM实现类的静态增强,可以无缝的部署于J2EE系统,对系统的开销几乎可以忽略

2)部署和使用非常的简单,整个Jwebap的部署只需要部署jwebap_core_**.jar以及需要使用的各种plugin_**.jar,然后配置jwebap.xml和web.xml就可以完成所有的部署,比起绝大多数的profiling容易的多。

同时Jwebap提供Web Console进行整个Jwebap的管理和数据展现。在API层提供一套默认的视图框架供plugin开发者使用,可以只用Jar包就开发出相当漂亮的Web界面。

3)Jwebap的开发分为两个部分Jwebap-core部分,Jwebap-plugin部分。core部分基于jdk14提供了类静态增强,轨迹生命管理,Plugin管理,视图框架等等,在这个基础上开发plugin。我觉得,好的profiling应该能够根据不同的人群按需使用,同时在功能不断复杂和强大的过程中仍然能够保证较轻的架子。

目前,0.5.8提供了基于jdk14的三个plugin:method监控,jdbc监控,http监控。这些可以算是基于plugin架构开发的示例。以后会开发更多的plugin,比如memory_monitor_plugin。甚至可以基于一些专属平台开发功能更强的插件。当然,Jwebap也可以不仅仅停留在profiling,日后,可以基于测试人员和质量保证,开发人员等方面开发适用的plugin,做到按需分配。


Jwebap的部署

Jwebap的部署相当简单,0.5.8版本提供了一个把plugin和core打在一起的包:jwebap_0.5.8_all.jar。然后对于jwebap.xml和web.xml的配置可以参看doc目录下的User-Guide。目前,0.5.8版本能够做到的功能有:

Jdbc监控:可以监控J2EE系统的所有Jdbc调用,包括Jndi数据源,可以过滤SQL时间,由哪些程序调用,哪些连接泄露。

Method监控:可以通过配置Method Plugin的'detect-class'参数,配置多个想要监控的包或类,Jwebap Console就可以跟踪这些类的方法执行,进行时间过滤,可以统计开销,和方法的调用堆栈,方法打开了多少Jdbc连接等等。

Http监控:可以监控http请求,进行时间过滤,可以进行请求的开销统计,请求打开了多少Jdbc连接等等。


贴几张示例图,有兴趣的朋友可以下载试用(jwebap.sourceforge.net),欢迎在这里进行交流:
  • 描述: Jdbc Traces 1
  • 大小: 148.2 KB
  • 描述: Jdbc Traces 2
  • 大小: 118.4 KB
  • 描述: Method Traces
  • 大小: 98.6 KB
分享到:
评论
112 楼 bluelover 2009-01-05  
不错的东西
111 楼 leasass 2008-11-06  
记号一下,有空要试试
110 楼 xpfly 2008-11-06  
启动时出现如下错误:我用的是weblogic8
<2008-11-6 15时21分50秒 GMT+08:00> <Notice> <WebLogicServer> <BEA-000327> <Starting WebLogic Admin Server "myserver" for domain "dmctais">
2008-11-06 15:22:28,600 INFO HttpComponent:44 [main] - httpcomponent startup.
2008-11-06 15:22:28,636 INFO MethodComponent:52 [main] - methodcomponent startup.
org.jwebap.toolkit.bytecode.InjectException: oracle.jdbc.driver.OracleDriver注入失败.
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.injectInternal(ASMInjectorStrategy.java:149)
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.inject(ASMInjectorStrategy.java:117)
        at org.jwebap.toolkit.bytecode.ClassEnhancer.createClass(ClassEnhancer.java:107)
        at org.jwebap.toolkit.bytecode.ClassEnhancer.createClass(ClassEnhancer.java:95)
        at org.jwebap.plugin.jdbc.JdbcComponent.injectJdbcDriver(JdbcComponent.java:133)
        at org.jwebap.plugin.jdbc.JdbcComponent.startup(JdbcComponent.java:62)
        at org.jwebap.core.context.RuntimeContext.registerComponent(RuntimeContext.java:51)
        at org.jwebap.core.Startup.startup(Startup.java:75)
        at org.jwebap.core.JwebapListener.contextInitialized(JwebapListener.java:33)
        at weblogic.servlet.internal.WebAppServletContext$FireContextListenerAction.run(WebAppServletContext.java:6781)
        at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
        at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
        at weblogic.servlet.internal.WebAppServletContext.notifyCreated(WebAppServletContext.java:1681)
        at weblogic.servlet.internal.WebAppServletContext.preloadResources(WebAppServletContext.java:3255)
        at weblogic.servlet.internal.WebAppServletContext.setStarted(WebAppServletContext.java:5949)
        at weblogic.servlet.internal.WebAppModule.start(WebAppModule.java:862)
        at weblogic.j2ee.J2EEApplicationContainer.start(J2EEApplicationContainer.java:2127)
        at weblogic.j2ee.J2EEApplicationContainer.activate(J2EEApplicationContainer.java:2168)
        at weblogic.j2ee.J2EEApplicationContainer.activate(J2EEApplicationContainer.java:2115)
        at weblogic.management.deploy.slave.SlaveDeployer$Application.setActivation(SlaveDeployer.java:3082)
        at weblogic.management.deploy.slave.SlaveDeployer.setActivationStateForAllApplications(SlaveDeployer.java:1751)
        at weblogic.management.deploy.slave.SlaveDeployer.resume(SlaveDeployer.java:359)
        at weblogic.management.deploy.DeploymentManagerServerLifeCycleImpl.resume(DeploymentManagerServerLifeCycleImpl.java:229)
        at weblogic.t3.srvr.SubsystemManager.resume(SubsystemManager.java:131)
        at weblogic.t3.srvr.T3Srvr.resume(T3Srvr.java:966)
        at weblogic.t3.srvr.T3Srvr.run(T3Srvr.java:361)
        at weblogic.Server.main(Server.java:32)
Caused by: org.jwebap.toolkit.bytecode.asm.DefineBytecodeException: oracle/jdbc/driver/OracleDriver注入错误:JVMCL048:redefine of class oracle/jdbc/driver/OracleDriver (&name=1134CECB0). old_cb=70000000017A3A0, new_cb=700000000433588, (&old_name=1134CECB0) old_name=oracle/jdbc/driver/OracleDriver
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.defineClass(ASMInjectorStrategy.java:305)
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.defineClass(ASMInjectorStrategy.java:215)
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.defineClass(ASMInjectorStrategy.java:201)
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.defineClass(ASMInjectorStrategy.java:201)
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.defineClass(ASMInjectorStrategy.java:201)
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.defineClass(ASMInjectorStrategy.java:201)
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.injectInternal(ASMInjectorStrategy.java:142)
        ... 26 more
Caused by: java.lang.LinkageError: JVMCL048:redefine of class oracle/jdbc/driver/OracleDriver (&name=1134CECB0). old_cb=70000000017A3A0, new_cb=700000000433588, (&old_name=1134CECB0) old_name=oracle/jdbc/driver/OracleDriver
        at java.lang.ClassLoader.defineClass0(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java(Compiled Code))
        at java.lang.ClassLoader.defineClass(ClassLoader.java:708)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java(Compiled Code))
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java(Compiled Code))
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java(Compiled Code))
        at java.lang.reflect.Method.invoke(Method.java(Compiled Code))
        at org.jwebap.toolkit.bytecode.asm.ASMInjectorStrategy.defineClass(ASMInjectorStrategy.java:302)
        ... 32 more
2008-11-06 15:22:29,143 WARN JdbcComponent:138 [main] - 对数据库驱动:oracle.jdbc.driver.OracleDriver的监听部署失败,不过这并不影响系统的运行。
109 楼 sharkdika 2008-08-12  
问个菜鸟问题
什么URL可以看到那个监控界面?
108 楼 mrjamesli 2008-06-04  
不好意思,已解决了,是驱动的jar包中有数字签名,删除数字签名就可以了
107 楼 xianyunheying 2008-06-04  
leadyu 写道
leadyu 写道
zbird 写道
我出这个问题
Caused by: java.lang.ClassCastException: org.jwebap.plugin.jdbc.TraceDetectConnection cannot be cast to oracle.jdbc.driver.OracleConnection
at oracle.jdbc.driver.OracleDriver.connect_$proxy(OracleDriver.java:345)
... 54 more


这个问题,我会尽快检查,可能是由于oracle驱动,内部有私有方法也返回Connection,而connect()方法内部去cast这个Connection(已经被jwebap代理过了),所以cast失败。


我刚才看了oracle驱动的源码,确实如我猜测的那样,这个bug,我明天发布jwebap_0.5.8_all_4.zip,请关注。

我写了个程序,也是这个问题。你能告诉我这个问题怎么解决吗?
106 楼 mrjamesli 2008-06-04  
我的系统是tomcat6,数据库是sqlserver2005,启动时显示:
2008-06-04 16:08:27,890 INFO HttpComponent:44 [main] - httpcomponent startup.
2008-06-04 16:08:28,078 INFO MethodComponent:52 [main] - methodcomponent startup
.
2008-06-04 16:08:28,234 INFO JdbcComponent:87 [main] - jdbccomponent startup.
2008-06-04 16:08:28,234 INFO Startup:81 [main] - jwebap component startup.

表明jwebap已经加载。但是连接池(dbcp)初始化时显示如下错误:
Cannot load JDBC driver class 'com.microsoft.sqlserver.jdbc.SQLServerDriver'
java.lang.SecurityException: class "com.microsoft.sqlserver.jdbc.SQLServerExcept
ion"'s signer information does not match signer information of other classes in
the same package
        at java.lang.ClassLoader.checkCerts(ClassLoader.java:775)
        at java.lang.ClassLoader.preDefineClass(ClassLoader.java:487)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:614)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
        at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1819)
        at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:872)
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1327)
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1206)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:164)
        at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:760)
        at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:540)
        。。。。。。。。。。。。。
这是什么原因啊
105 楼 jxb8901 2008-04-11  
不好意思,已解决了,是我自己配置的问题。
104 楼 zbird 2008-03-28  
汇总统计里面最好也能加个清零的功能。
如果系统运行了很久,可能在后期边慢了。
但前面的基数比较大,看上去平均值变化不到。
如果加个清理的功能就可以了解相对实时的统计数据了。
103 楼 zhuyx808 2008-03-27  
最好是吧这些数据写成日志或者写进数据库,另外在增加一个写不写进的开关,因为这个数据都是固定的,建数据库表也比较固定了
102 楼 dream实现 2008-03-26  
我也想汉化一下,感觉这东西确实不错,不过修改了一下那个模板,不论怎么设置编码,修改后都是乱码,那个是common template的模板,请赐教一下,该如何设置
101 楼 zhuyx808 2008-03-26  
乱码问题怎麽解决?
100 楼 ajoo 2008-03-26  
用cglib的FastMethod,会快不少。另外,如果不需要做around interceptor。用cglib的Dispatcher接口,效率几乎可以赶上直接的虚函数调用。
99 楼 leadyu 2008-03-25  
myreligion 写道

我倒是希望能找到一个可以对执行的sql语句进行分类汇总的软件,可以统计好比有多少sql执行了多少次,每个sql语句的平均时间是多少。类似于oracle的查询分析工具。一直在用mysql,缺少这类东西,不知道Jwebap可否满足?


jwebap以后所有的监控功能都是plugin,现在的三个plugin还很基础,如果你有plugin的想法,欢迎交流^_^
98 楼 leadyu 2008-03-25  
meikefu 写道
看到这个接口MethodInjectHandler.invoke传入的是java.lang.reflect.Method,源码中的2个实现类JdbcDriverInjectHandle,TraceMethodHandle,前者是after,后者是before.
看了看源码jwebapp,没有注入原方法,而是proxy原方法,如果以一个方法为元单位,除了before和after还有什么形式的注入?
数据库连接应该是一个系统的核心,如果在关键模块大量运用反射会导致性能下降


会有更复杂的需求的,比如JdbcDriverInjectHandle,包装返回对象:

Object o;
		try {
			o = methodProxy.invoke(target, args);
		} catch (InvocationTargetException e) {
			// 抛出原有异常
			throw e.getCause();
		} finally {

		}
		if (!Modifier.isPrivate(method.getModifiers())
				&& Connection.class.equals(method.getReturnType())
				&& o instanceof Connection
				&& !(o instanceof TraceDetectConnection)) {
			return new TraceDetectConnection(_container, (Connection) o,
					_listeners);
		} else if (!Modifier.isPrivate(method.getModifiers())
				&& DataSource.class.equals(method.getReturnType())
				&& o instanceof DataSource
				&& !(o instanceof TraceDetectDataSource)) {
			return new TraceDetectDataSource(_container, (DataSource) o,
					_listeners);
		} else {
			return o;
		}


以后,会有更复杂的场景,至于反射带来了多大开销,起码从目前,我在几个电信省级生产系统的应用来看,没有感觉,当然以后,我觉得还需要细致的性能测试,我希望jwebap能够更多的应用于生产系统,这样才能真正解决问题(在几个存在性能问题的电信省级生产系统的应用中已经起到了很大的作用)

97 楼 meikefu 2008-03-25  
引用
生产环境应当没谁会去挂一个性能监视平台吧。
我觉得性能监视平台的效率只要不低到影响测试结果就不用做这么多考虑。

不在生产环境上面监控在那里监控?刚才测试一下
public Integer step(Integer value)
	{
		return new Integer(value.intValue()*value.intValue());
	}
	
	public int callReferenceArgs(int loops) {
	    TimingClass timing = new TimingClass();
	    Integer value = new Integer(1234);
	    for (int index = 0; index < loops; index++) {
	        value = timing.step(value);
	    }
	    return value.intValue();
	}
	public int callReflectArgs(int loops) {
	    TimingClass timing = new TimingClass();
	    try {
	        Method method = TimingClass.class.getMethod
	            ("step", new Class [] { Integer.class });
	        Object[] args = new Object[1];
	        Object value = new Integer(1234);
	        for (int index = 0; index < loops; index++) {
	            args[0] = value;
	            value = method.invoke(timing, args);
	        }
	        return ((Integer)value).intValue();
	    } catch (Exception e) {
	        e.printStackTrace();
	    	return 0;
	    }
	}
	
	public static void main(String[] args) throws Exception
	{
		TimingClass tc = new TimingClass();
		int loop = 1000000;
		
		long a = System.currentTimeMillis();
		tc.callReferenceArgs(loop);
		System.out.println("引用调用:"+(System.currentTimeMillis() -a));
		
		long b = System.currentTimeMillis();
		tc.callReflectArgs(loop);
		System.out.println("反射调用:"+(System.currentTimeMillis() -b));
	}

在jre1.4下引用调用:31反射调用:219,差距有7倍左右.但是单位是毫秒,如果并发量不大应该整个系统的瓶颈应该不会在这里,只是为了探讨一下性能问题.


能否考虑接入jmx的mbean监控webserver的连接池,线程池,jms,jta,etc期待MemoryComponent,希望jwebapp更好更强
96 楼 myreligion 2008-03-25  

我倒是希望能找到一个可以对执行的sql语句进行分类汇总的软件,可以统计好比有多少sql执行了多少次,每个sql语句的平均时间是多少。类似于oracle的查询分析工具。一直在用mysql,缺少这类东西,不知道Jwebap可否满足?
95 楼 zbird 2008-03-25  
生产环境应当没谁会去挂一个性能监视平台吧。
我觉得性能监视平台的效率只要不低到影响测试结果就不用做这么多考虑。
94 楼 meikefu 2008-03-25  
看到这个接口MethodInjectHandler.invoke传入的是java.lang.reflect.Method,源码中的2个实现类JdbcDriverInjectHandle,TraceMethodHandle,前者是after,后者是before.
看了看源码jwebapp,没有注入原方法,而是proxy原方法,如果以一个方法为元单位,除了before和after还有什么形式的注入?
数据库连接应该是一个系统的核心,如果在关键模块大量运用反射会导致性能下降
93 楼 leadyu 2008-03-25  
meikefu 写道
jwebapp注入的方法都使用反射Method.invoke来调用源方法,开销比较大,如果换成直接调用是否能降低开销


没有那么简单,对于原方法的调用是可以直接调用而且实现起来简单的多,但是这样只能实现,before和after的注入,注入的功能大大减弱。

所以,出于这点的考虑,jwebap简单的实现了invokeHandle的注入方式(还有需要改进的地方,比如多handle注入),可以用的很灵活,有兴趣的话可以参考JdbcComponent插件里面的JdbcInvokeHandle的运用方法。

相关推荐

    oracle 10.2.0.5.8

    Oracle 10.2.0.5.8 是Oracle数据库的一个特定版本,它包含了重要的修复和性能优化。Oracle数据库是全球广泛使用的大型企业级关系型数据库管理系统,由Oracle公司开发和维护。此版本的发布旨在解决之前版本中发现的...

    GPU-Z.0.5.8 汉化版

    总的来说,GPU-Z.0.5.8汉化版是每个关心电脑硬件性能的用户必备的工具之一,它提供的详尽信息和实时监控能力,使得用户能够更好地了解和管理他们的GPU,从而提升系统的稳定性和效率。无论是日常使用还是专业需求,...

    GPU-Z.0.5.8

    GPU-Z.0.5.8显卡详细显示工具自己试试

    Python库 | cobra-0.5.8-cp27-cp27mu-manylinux1_x86_64.whl

    标题中的"Python库 | cobra-0.5.8-cp27-cp27mu-manylinux1_x86_64.whl"指的是Python的一个特定版本的库——cobra,其版本号为0.5.8,适用于Python 2.7解释器(由"cp27"表示)且包含mu多线程支持。"manylinux1_x86_64...

    soljson-v0.5.8 commit.23d335f2.js

    soljson-v0.5.8 commit.23d335f2.js soljson-v0.5.8 commit.23d335f2.js

    Python库 | BentoML-0.5.8.tar.gz

    6. **监控和日志**:BentoML集成了Prometheus和Grafana等监控工具,帮助开发者实时了解服务状态,及时发现和解决问题。 7. **扩展性**:BentoML的插件系统允许开发者自定义服务行为,例如添加自定义预处理或后处理...

    PyPI 官网下载 | gear-0.5.8.tar.gz

    标题中的“PyPI 官网下载 | gear-0.5.8.tar.gz”指的是Python的包索引(PyPI)上发布的gear版本为0.5.8的源代码压缩包,其格式为tar.gz。PyPI是Python开发者发布和分享自己开发的软件包的官方平台,方便其他用户通过...

    Blueprint css框架2013年最新可视化操作工具-boks-v0.5.8

    最新版div+css可视化开发工具,boks-v0.5.8,适用于blueprint css框架的开发,拖拉拽即可导出漂亮的网页架构。

    PyPI 官网下载 | djangorestsearch-0.5.8.tar.gz

    《PyPI官网下载 | djangorestsearch-0.5.8.tar.gz——探索Python库的奥秘》 PyPI(Python Package Index),是Python开发者最重要的资源库,它提供了丰富的Python库,供全球开发者免费下载和使用。本次我们将关注的...

    oracle 10.2.0.5.0 ~10.2.0.5.8

    - **测试与监控**:升级后,进行性能测试和功能验证,监控数据库运行状态,确保一切正常。 5. **注意事项**: - 在升级前,详细阅读Oracle的官方文档,了解补丁的具体变更内容和升级步骤。 - 升级过程中应遵循...

    Python库 | runway-python-0.5.8.tar.gz

    4. **可视化界面**:Runway提供了一个用户友好的Web界面,可以实时监控模型的输入、输出和性能指标,帮助开发者调试和优化模型。 5. **集成其他工具**:Runway与Jupyter Notebook、TensorBoard等流行开发工具集成,...

    PyPI 官网下载 | dmsa-0.5.8.tar.gz

    标题中的“PyPI 官网下载 | dmsa-0.5.8.tar.gz”表明这是一个在Python Package Index(PyPI)上发布的软件包。PyPI是Python开发者用来分享和发现第三方库的官方平台,它使得用户能够方便地通过pip(Python的包管理器...

    PyPI 官网下载 | botnoi-0.5.8.tar.gz

    PyPI是Python开发者发布自己编写的Python库或项目的平台,使得全球的Python用户都能方便地安装和使用。这里的"botnoi-0.5.8.tar.gz"是该库的一个具体版本,0.5.8代表了版本号,而".tar.gz"是文件的压缩格式,表明这...

    PyPI 官网下载 | jupyterhubutils-0.5.8-py2.py3-none-any.whl

    随着JupyterHub的版本更新,`jupyterhubutils`也会定期发布新版本,以保持与最新JupyterHub版本的兼容性,并添加新的功能和修复已知问题。开发者应定期检查更新,确保使用的版本是最新的,以获得最佳的稳定性和功能...

    PyPI 官网下载 | monobox-0.5.8.tar.gz

    标题中的"PyPI 官网下载 | monobox-0.5.8.tar.gz"表明这是一个在Python Package Index(PyPI)官方源上发布的软件包,名为`monobox`,版本号为0.5.8,且以tar.gz格式提供。在Python社区中,PyPI是开发者分享和获取...

    Python库 | dagster_graphql-0.5.8.tar.gz

    这个0.5.8版本可能包含对库的改进和修复,比如性能优化、新的功能添加或者已知问题的解决。在使用这个库之前,开发者需要先将其解压,然后通过Python的pip或其他安装工具进行安装,例如: ```bash pip install . ```...

    wpa_supplicant-0.5.8.tar.gz

    《wpa_supplicant-0.5.8:无线网络连接的关键组件》 在现代计算机系统中,无线网络连接已经成为不可或缺的一部分。特别是在Linux操作系统中,为了实现安全、稳定的无线连接,wpa_supplicant扮演了至关重要的角色。...

    OpenCore-0.5.8

    OpenCore是类似于Clover的UEFI的引导器,OpenCore提供了详细的日志系统,帮助黑苹果排错;其次OpenCore以更先进的方法注入第三方Kext,不破坏系统的SIP;再次,OpenCore支持读取NVRAM等一系列特性,可以让黑苹果变得...

    PyPI 官网下载 | cy-0.5.8.tar.gz

    《PyPI官网下载 | cy-0.5.8.tar.gz:深入理解Python库的发布与使用》 在Python的世界里,PyPI(Python Package Index)是最重要的资源库,它为全球的开发者提供了一个集中地,可以发布、分享并下载Python软件包。...

Global site tag (gtag.js) - Google Analytics