`
kabike
  • 浏览: 611050 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

clojure中的agent实现

 
阅读更多
最近看了下clojure的并发,其中提到了agent.agent的原理是把对agent的action提交到线程池中运行.它保证线程安全的措施是对每一个agent,同时只有一个actio
在运行.

下面做一个简单的对比,多个线程多次对同一个StringBuilder进行append,如果不同步,结果是不正确的.
		final StringBuilder sb = new StringBuilder();
		ExecutorService pool = Executors.newFixedThreadPool(Runtime
				.getRuntime().availableProcessors() + 2);
		for (int i = 0; i < THREAD_NUMBER; i++) {
			pool.submit(new Runnable() {
				@Override
				public void run() {
					for (int j = 0; j < ITERATION_NUMBER; j++) {
						sb.append(bar);
					}
				}

			});
		}
		pool.shutdown();
		pool.awaitTermination(60, TimeUnit.SECONDS);
		String s = sb.toString();
		System.out.println(s.length() / bar.length());

输出结果不是ITERATION_NUMBER * THREAD_NUMBER

可以用synchronized或者java 1.5里的lock来同步,也可以仿照agent的原理,不使用同步机制,而是让action顺序执行

结果表明,让action顺序执行,而不使用lock或者synchronized等手段,效率确实比较高.


package foo.concurrency;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ClojureAgent {

	private static String bar = "log from full line a very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long line\n";

	private static int ITERATION_NUMBER = 4000;

	private static int THREAD_NUMBER = 6;

	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		base();
		System.out.println("time is " + (System.currentTimeMillis() - start));
		start = System.currentTimeMillis();
		sync();
		System.out.println("time is " + (System.currentTimeMillis() - start));
		start = System.currentTimeMillis();
		lock();
		System.out.println("time is " + (System.currentTimeMillis() - start));
		start = System.currentTimeMillis();
		pool();
		System.out.println("time is " + (System.currentTimeMillis() - start));
	}

	private static void pool() throws Exception {

		final StringBuilder sb = new StringBuilder();
		ExecutorService pool = Executors.newFixedThreadPool(Runtime
				.getRuntime().availableProcessors() + 2);
		for (int i = 0; i < THREAD_NUMBER; i++) {
			pool.submit(new Callable<Object>() {

				@Override
				public Object call() throws Exception {
					for (int j = 0; j < ITERATION_NUMBER; j++) {
						sb.append(bar);
					}
					return null;
				}

			}).get();
		}
		pool.shutdown();
		pool.awaitTermination(60, TimeUnit.SECONDS);
		String s = sb.toString();
		System.out.println(s.length() / bar.length());
	}

	private static void sync() throws Exception {

		final StringBuilder sb = new StringBuilder();
		ExecutorService pool = Executors.newFixedThreadPool(Runtime
				.getRuntime().availableProcessors() + 2);
		for (int i = 0; i < THREAD_NUMBER; i++) {
			pool.submit(new Runnable() {
				@Override
				public void run() {

					for (int j = 0; j < ITERATION_NUMBER; j++) {
						synchronized (sb) {
							sb.append(bar);
						}
					}

				}

			});
		}
		pool.shutdown();
		pool.awaitTermination(60, TimeUnit.SECONDS);
		String s = sb.toString();
		System.out.println(s.length() / bar.length());
	}

	private static void lock() throws Exception {
		final Lock lock = new ReentrantLock();
		final StringBuilder sb = new StringBuilder();
		ExecutorService pool = Executors.newFixedThreadPool(Runtime
				.getRuntime().availableProcessors() + 2);
		for (int i = 0; i < THREAD_NUMBER; i++) {
			pool.submit(new Runnable() {
				@Override
				public void run() {

					for (int j = 0; j < ITERATION_NUMBER; j++) {
						lock.lock();
						try {
							sb.append(bar);
						} finally {
							lock.unlock();
						}
					}
				}

			});
		}
		pool.shutdown();
		pool.awaitTermination(60, TimeUnit.SECONDS);
		String s = sb.toString();
		System.out.println(s.length() / bar.length());
	}

	private static void base() throws Exception {

		final StringBuilder sb = new StringBuilder();
		ExecutorService pool = Executors.newFixedThreadPool(Runtime
				.getRuntime().availableProcessors() + 2);
		for (int i = 0; i < THREAD_NUMBER; i++) {
			pool.submit(new Runnable() {
				@Override
				public void run() {
					for (int j = 0; j < ITERATION_NUMBER; j++) {
						sb.append(bar);
					}
				}

			});
		}
		pool.shutdown();
		pool.awaitTermination(60, TimeUnit.SECONDS);
		String s = sb.toString();
		System.out.println(s.length() / bar.length());
	}
}
0
1
分享到:
评论

相关推荐

    Clojure入门教程.pdf

    - **并发模型**:Clojure提供了原子、代理(agent)、参考(reference)等机制,用于实现高效的并发编程。 - **并行编程**:通过利用不可变数据结构和函数式编程的特性,Clojure简化了并行编程的复杂度。 #### 七、高级...

    Clojure中的维护状态:Clojure中的有状态数据示例

    在Clojure中,状态管理是编程的一个重要方面,特别是对于那些需要处理持久化或变化数据的应用程序。Clojure,作为一种Lisp方言,以其对函数式编程的强调而著名,但同样也提供了处理状态的能力。本篇文章将深入探讨...

    clojure-basics-源码.rar

    4. **引用与原子性**:Clojure中的`ref`、`agent`和`atom`是处理并发的工具。其中,`atom`是最基础的,用于管理可变状态,具有原子性操作。 5. **宏**(Macros):Clojure允许用户创建自己的语法,这是Lisp家族的一...

    clojure-rust:Clojure转换为Rust编译器

    - **并行和并发**:Clojure的future和agent需要考虑如何在Rust中实现线程安全和异步操作。 项目`clojure-rust-master`可能包含以下内容: - **源代码**:编译器的实现,通常包括解析器、转换器和代码生成器的源代码...

    user-agent:Clojure的用户代理解析器

    在`user-agent-master`这个项目中,很可能包含了上述步骤的实现,通过阅读源代码,我们可以深入理解Clojure如何处理字符串解析问题,以及如何构建高效的函数式程序。对于Clojure开发者来说,这是一个学习和实践的好...

    clojure-tensorflow-interop:如何在Clojure中运行TensorFlow

    本文将深入探讨如何在Clojure环境中运行TensorFlow,利用Java互操作性(Java-Interop)来实现这一目标。 首先,理解Clojure与Java的互操作性是关键。由于Clojure是构建在JVM上的,因此可以直接调用Java库,包括...

    clojure-1.3.0

    Clojure 1.3.0 是一个重要的版本更新,它基于 Lisp 编程语言的现代实现,专注于在Java平台上提供高效、并发和功能性的编程体验。这个版本在Clojure的历史发展中扮演了关键的角色,引入了许多改进和新特性,旨在提升...

    water-symbol:Clojure中使用s-expresso游戏引擎的小型自上而下策略游戏

    利用Clojure的agent、ref和atom等核心并发工具,开发者可以在不引入传统并发问题(如竞态条件和死锁)的情况下,轻松地处理游戏中的并行任务,如更新多个游戏实体的状态或执行异步I/O操作。 至于项目本身,"water-...

    温柔的clojure:David Touretzky的书Common Lisp:符号计算的温和介绍(Clojure实现)中的练习

    《温柔的Clojure》是基于David Touretzky的著作《Common Lisp:符号计算的温和介绍》的一系列练习,现在我们将其转化为Clojure语言来实现。这个资源旨在帮助读者深入理解Clojure这门函数式编程语言,同时也为那些...

    cloture:常见Lisp中的Clojure

    Cloture是Common Lisp中Clojure的实现。 首先,它旨在与Common Lisp良好地互操作。 Lijup阅读器读取Clojure,而Clojure名称空间是Lisp包。 Cloture处于非常早期的阶段(pre-alpha),但是它已经发展到足以加载,...

    clojure:Clojure编程语言

    3. **Agents**:`agent` 用于异步更新,它们在后台线程中执行任务,简化了异步编程。 ### 四、与 Java 平台的融合 1. **Interop with Java**:Clojure 可以无缝集成 Java 代码,可以直接调用 Java 类库,使得 ...

    clojure-examples:杂项 clojure 示例

    - **动态性**:Clojure 允许在运行时改变变量的值,通过 var 和 binding 实现。 - **引用类型**:ref、atom、agent 和 promise 用于并发编程,它们保证了状态的一致性和协调。 - **多态性**:Clojure 的协议...

    clojure-workshop-guide:使用Clojure进行功能编程的材料

    `agent`和`atom`是Clojure中处理并发的两种主要方式,它们提供了一种安全地更新共享状态的方式。 7. **ClojureScript**:Clojure也有一个用于编写JavaScript的版本,称为ClojureScript,它允许Clojure代码编译成...

    uritemplate-clj:URI模板的Clojure实现,如RFC 6570(http

    符合RFC 6570( )中指定的URI模板的Clojure实现,符合级别4 uritemplate uritemplate-clj首先公开uritemplate函数,以URI模板和值映射为输入并返回填充的模板: user=&gt; ( ns test # _=&gt; ( :require [uri...

    拥抱Clojure

    - **Ref** 和 **Agent**:Clojure的并发模型还包括`Ref`(用于协调多个并发修改)和`Agent`(异步更新)。 6. **REPL驱动开发** - **读-求值-打印循环(REPL)**:Clojure的核心开发工具,允许快速测试代码,迭代...

    clojure-through-code:Clojure代码示例,用于解释语言的核心方面-通常在REPL中进行评估

    然而,为了处理状态,Clojure引入了`ref`、`atom`、`agent`等引用类型,它们提供了一种受控的状态变化机制,确保了并发安全。 5. **宏与元编程** Clojure的Lisp特性体现在其强大的宏系统,宏可以在编译时生成代码...

    clojurebits:涉足Clojure

    其中,向量和映射都是可变的,但可以通过创建不可变数据结构(如PersistentVector和PersistentHashMap)来实现高效的更新操作,这是Clojure处理并发的关键。 Clojure提供了丰富的内置函数和宏,如`map`、`reduce`、...

Global site tag (gtag.js) - Google Analytics