Re: threads?

2010-10-24 Thread Christian Mueller
I would implement threads in the following form

$thread_counter = 0;
$global = lock;

$thread = new thread( \thread_sub );
$thread-start();

thread_sub {
lock( $global ) {
print i'm thread , ++$thread_counter, \n;
}
}

It's a mixture of ithreads and the C# threading model. The thread works in
the same interpreter. You have to do locking by yourself. That would make
it light weighted and gives you the power to do everything you want. I
don't think that normal threads are very difficult to understand. But it
gives the highest flexibility.




Re: threads?

2010-10-22 Thread Aaron Sherman
On Thu, Oct 21, 2010 at 6:04 PM, Darren Duncan dar...@darrenduncan.netwrote:

 Aaron Sherman wrote:



 Things that typically precipitate threading in an application:

   - Blocking IO
   - Event management (often as a crutch to avoid asynchronous code)
   - Legitimately parallelizable, intense computing

 Interestingly, the first two tend to be where most of the need comes from
 and the last one tends to be what drives most discussion of threading.



 The last one in particular would legitimately get attention when one
 considers that it is for this that the concern about using multi-core
 machines efficiently comes into play.


That sounds great, but what's the benefit to a common use case? Sorting
lists with higher processor overhead and waste heat in applications that
traditionally weren't processor-bound in the first place?

Over the past 20+ years, I've seen some very large, processor-bound
applications that could (and in some cases, did) benefit from threading over
multiple cores. However, they were so far in the minority as to be nearly
invisible, and in many cases such applications can simply be run multiple
times per host in order to VERY efficiently consume every available
processor.

The vast majority of my computing experience has been in places where I'm
actually willing to use Perl, a grossly inefficient language (I say this,
coming as I do from C, not in comparison to other HLLs), because my
performance concerns are either non-existent or related almost entirely to
non-trivial IO (i.e. anything sendfile can do).


  The first 2 are more about lowering latency and appearing responsive to a
 user on a single core machine.


Write me a Web server, and we'll talk. Worse, write a BitTorrent client that
tries to store its results into a high performance, local datastore without
reducing theoretical, back-of-the-napkin throughput by a staggering amount.
Shockingly enough, neither of these frequently used examples are
processor-bound.

The vast majority of today's applications are written with network
communications in mind to one degree or another. The user, isn't so much
interesting as servicing network and disk IO responsively enough that
hardware and network protocol stacks wait on you to empty or fill a buffer
as infrequently as possible. This is essential in such rare circumstances
as:

   - Database intensive applications
   - Moving large data files across wide area networks
   - Parsing and interpreting highly complex languages inline from
   data received over multiple, simultaneous network connections (sounds like
   this should be rare, but your browser does it every time you click on a
   link)

Just in working with Rakudo, I have to use git, make and Perl itself, all of
which can improve CPU performance all they like, but will ultimately run
slow if they don't handle reading dozens of files, possibly from multiple IO
devices (disks, network filesystems, remote repositories, etc) as
responsively as possible.

Now, to back up and think this through, there is one place where multi-core
processor usage is going to become critical over the next few years: phones.
Android-based phones are going multi-core within the next six months. My
money is on a multi-core iPhone within a year. These platforms are going to
need to take advantage of multiple cores for primarily single-application
performance in a low-power environment.

So, I don't want you to think that I'm blind to the need you describe. I
just don't want you to be unrealistic about the application balance out
there.


 I think that Perl 6's implicit multi-threading approach such as for
 hyperops or junctions is a good best first choice to handle many common
 needs, the last list item above, without users having to think about it.
  Likewise any pure functional code. -- Darren Duncan


It's very common for people working on the design or implementation of a
programming language to become myopic with respect to the importance of
executing code as quickly as possible, and I'm not faulting anyone for that.
It's probably a good thing in most circumstances, but in this case, assuming
that the largest need is going to be the execution of code turns out to be a
misleading instinct. Computers execute code far, far less than you would
expect, and the cost of failing to service events is often orders of
magnitude greater than the cost of spending twice the number of cycles doing
so.

PS: Want an example of how important IO is? Google has their own multi-core
friendly network protocol modifications to Linux that have been pushed out
in the past 6 months:

http://www.h-online.com/open/features/Kernel-Log-Coming-in-2-6-35-Part-3-Network-support-1040736.html

They had to do this because single cores can no longer keep up with the
network.


Re: threads?

2010-10-21 Thread Aaron Sherman
I've done quite a lot of concurrent programming over the past 23ish years,
from the implementation of a parallelized version of CLIPS back in the late
80s to many C, Perl, and Python projects involving everything from shared
memory to process pooling to every permutation of hard and soft thread
management. To say I'm rusty, however, would be an understatement, and I'm
sure my information is sorely out of date.

What I can contribute to such a conversation, however, is this:

   - Make the concept of process and thread an implementation detail
   rather than separate worlds and your users won't learn to fear one or the
   other.
   - If the programmer has to think about semaphore management, there's
   already a problem.
   - If the programmer's not allowed to think about semaphore management,
   there's already a problem.
   - Don't paint yourself into a corner when it comes to playing nice with
   local interfaces.
   - If your idea of instantiating a thread involves creating a on OS VM,
   then you're probably lighter weight than Python's threading model, but I'd
   suggesting parring it down some more. It's thread, not ringworld (I was
   going to say not 'space elevator,' but it seemed insufficient to the
   examples I've seen).


I know that's pretty high-level, but it's what I've got. I think I wrote my
last threaded application in 2007.


Re: threads?

2010-10-21 Thread Aaron Sherman
On Tue, Oct 12, 2010 at 10:22 AM, Damian Conway dam...@conway.org wrote:


 Perhaps we need to think more Perlishly and reframe the entire question.
 Not: What threading model do we need?, but: What kinds of non-sequential
 programming tasks do we want to make easy...and how would we like to be
 able to specify those tasks?


Things that typically precipitate threading in an application:

   - Blocking IO
   - Event management (often as a crutch to avoid asynchronous code)
   - Legitimately parallelizable, intense computing

Interestingly, the first two tend to be where most of the need comes from
and the last one tends to be what drives most discussion of threading.

Perhaps it would make more sense to discuss Perl 6's event model (glib,
IMHO, is an excellent role model, here --
http://en.wikipedia.org/wiki/Event_loop#GLib_event_loop ) and async IO model
before we deal with how to sort a list on 256 cores...


Re: threads?

2010-10-21 Thread Darren Duncan

Aaron Sherman wrote:

On Tue, Oct 12, 2010 at 10:22 AM, Damian Conway dam...@conway.org wrote:

Perhaps we need to think more Perlishly and reframe the entire question.
Not: What threading model do we need?, but: What kinds of non-sequential
programming tasks do we want to make easy...and how would we like to be
able to specify those tasks?


Things that typically precipitate threading in an application:

   - Blocking IO
   - Event management (often as a crutch to avoid asynchronous code)
   - Legitimately parallelizable, intense computing

Interestingly, the first two tend to be where most of the need comes from
and the last one tends to be what drives most discussion of threading.

Perhaps it would make more sense to discuss Perl 6's event model (glib,
IMHO, is an excellent role model, here --
http://en.wikipedia.org/wiki/Event_loop#GLib_event_loop ) and async IO model
before we deal with how to sort a list on 256 cores...


The last one in particular would legitimately get attention when one considers 
that it is for this that the concern about using multi-core machines efficiently 
comes into play.  The first 2 are more about lowering latency and appearing 
responsive to a user on a single core machine.  I think that Perl 6's implicit 
multi-threading approach such as for hyperops or junctions is a good best first 
choice to handle many common needs, the last list item above, without users 
having to think about it.  Likewise any pure functional code. -- Darren Duncan


Re: threads?

2010-10-18 Thread Tim Bunce
On Sun, Oct 17, 2010 at 01:18:09AM +0200, Carl Mäsak wrote:
 Damian (), Matt ():
  Perhaps we need to think more Perlishly and reframe the entire question.
  Not: What threading model do we need?, but: What kinds of non-sequential
  programming tasks do we want to make easy...and how would we like to be
  able to specify those tasks?
 
  I watched a presentation by Guy Steele at the Strange Loop conference on
  Thursday where he talked about non-sequential programming.  One of the
  interesting things that he mentioned was to use the algebraic properties of 
  an
  operation to know when a large grouping of operations can be done 
  non-sequentially.
  For example, we know that the meta reduction operator could take very large 
 lists
  and split them into smaller lists across all available cores when 
  performing certain
  operations, like addition and multiplication.  If we could mark new 
  operators that
  we create with this knowledge we could do this for custom operators too.  
  This isn't
  a new idea, but it seems like it would be a helpful tool in simplifying 
  non-sequential
  programming and I didn't see it mentioned in this thread yet.
 
 This idea seems to be in the air somehow. (Even though all copies of
 the meme might have its roots in that Guy you mention.)
 
  http://irclog.perlgeek.de/perl6/2010-10-15#i_2914961
 
 Perl 6 has all the prerequisites for making this happen. It's mostly a
 question of marking things up with some trait or other.
 
 our multi sub infix:+($a, $b) will optimizeassociativity {
 ...
 }
 
 (User-defined ops can be markes in exactly the same way.)
 
 All that's needed after that is a reduce sub that's sensitive to such
 traits. Oh, and threads.

Minimizing the overhead of such a mechanism would be crucial to making
it beneficial for use on non-massive data sets.

For this kind of thing to work well we'd need to have multiple threads
able to work in a single interpreter.

Tim.


Re: threads?

2010-10-16 Thread Carl Mäsak
Damian (), Matt ():
 Perhaps we need to think more Perlishly and reframe the entire question.
 Not: What threading model do we need?, but: What kinds of non-sequential
 programming tasks do we want to make easy...and how would we like to be
 able to specify those tasks?

 I watched a presentation by Guy Steele at the Strange Loop conference on
 Thursday where he talked about non-sequential programming.  One of the
 interesting things that he mentioned was to use the algebraic properties of an
 operation to know when a large grouping of operations can be done 
 non-sequentially.
 For example, we know that the meta reduction operator could take very large 
lists
 and split them into smaller lists across all available cores when performing 
 certain
 operations, like addition and multiplication.  If we could mark new operators 
 that
 we create with this knowledge we could do this for custom operators too.  
 This isn't
 a new idea, but it seems like it would be a helpful tool in simplifying 
 non-sequential
 programming and I didn't see it mentioned in this thread yet.

This idea seems to be in the air somehow. (Even though all copies of
the meme might have its roots in that Guy you mention.)

 http://irclog.perlgeek.de/perl6/2010-10-15#i_2914961

Perl 6 has all the prerequisites for making this happen. It's mostly a
question of marking things up with some trait or other.

our multi sub infix:+($a, $b) will optimizeassociativity {
...
}

(User-defined ops can be markes in exactly the same way.)

All that's needed after that is a reduce sub that's sensitive to such
traits. Oh, and threads.

// Carl


Re: threads?

2010-10-16 Thread Matt Follett
On Oct 12, 2010, at 9:22 AM, Damian Conway wrote:

 Perhaps we need to think more Perlishly and reframe the entire question.
 Not: What threading model do we need?, but: What kinds of non-sequential
 programming tasks do we want to make easy...and how would we like to be
 able to specify those tasks?

I watched a presentation by Guy Steele at the Strange Loop conference on 
Thursday where he talked about non-sequential programming.  One of the 
interesting things that he mentioned was to use the algebraic properties of an 
operation to know when a large grouping of operations can be done 
non-sequentially.  For example, we know that the meta reduction operator could 
take very large lists and split them into smaller lists across all available 
cores when performing certain operations, like addition and multiplication.  If 
we could mark new operators that we create with this knowledge we could do this 
for custom operators too.  This isn't a new idea, but it seems like it would be 
a helpful tool in simplifying non-sequential programming and I didn't see it 
mentioned in this thread yet.

Here are the slides to the talk to which I'm referring:
http://strangeloop2010.com/talk/presentation_file/14299/GuySteele-parallel.pdf

~Matt

Re: threads?

2010-10-13 Thread Andy_Bach
I haven't enough smarts to see if this is at all what you're looking for 
but is used some of the same terms:

http://dpj.cs.uiuc.edu/DPJ/Home.html?cid=nl_ddjupdate_2010-10-12_html

Welcome to the home page for the Deterministic Parallel Java (DPJ) project 
at the University of Illinois at Urbana-Champaign.  
Project Overview
The broad goal of our project is to provide deterministic-by-default 
semantics for an object-oriented, imperative parallel language, using 
primarily compile-time checking.  ?Deterministic? means that the program 
produces the same visible output for a given input, in all executions.  
?By default? means that deterministic behavior is guaranteed unless the 
programmer explicitly requests nondeterminism.  This is in contrast to 
today?s shared-memory programming models (e.g., threads and locks), which 
are inherently nondeterministic and can even have undetected data races.  
Our paper at HotPar 2009 states our research goals in more detail.  The 
other pages of this site provide additional information about the DPJ type 
system and language.
a
--
Andy Bach
Systems Mangler
Internet: andy_b...@wiwb.uscourts.gov
Voice: (608) 261-5738; 
Cell: (608) 658-1890

No, no, you're not thinking, you're just being logical.
-Niels Bohr, physicist (1885-1962)

Re: threads?

2010-10-13 Thread B. Estrade
On Tue, Oct 12, 2010 at 10:43:44PM +0200, Leon Timmermans wrote:
 On Tue, Oct 12, 2010 at 4:22 PM, Damian Conway dam...@conway.org wrote:
  The problem is: while most people can agree on what have proved to be
  unsatisfactory threading models, not many people can seem to agree on
  what would constititute a satisfactory threading model (or, possibly, 
  models).
 
  What we really need is some anecdotal evidence from folks who are actually
  using threading in real-world situations (in *any* languages). What has 
  worked
  in practice? What has worked well? What was painful? What was error-prone?
  And for which kinds of tasks?
 
 Most languages either implement concurrency in a way that's not very
 useful (CPython, CRuby) or implement it in a way that's slightly
 (Java/C/C++) to totally (perl 5) insane. Erlang is the only language
 I've worked with whose threads I really like, but sadly it's rather
 weak at a lot of other things.
 
 In general, I don't feel that a shared memory model is a good fit for
 a high level language. I'm very much a proponent of message passing.
 Unlike shared memory, it's actually easier to do the right thing than
 not. Implementing it correctly and efficiently is not easier than
 doing a shared memory system though in my experience (I'm busy
 implementing it on top of ithreads; yeah I'm masochist like that).
 
  And we also need to stand back a little further and ask: is threading
  the right approach at all? Do threads work in *any* language? Are there
  better metaphors?
 
  Perhaps we need to think more Perlishly and reframe the entire question.
  Not: What threading model do we need?, but: What kinds of non-sequential
  programming tasks do we want to make easy...and how would we like to be
  able to specify those tasks?
 
 I agree. I would prefer implicit over explicit concurrency wherever possible.

I know you're speaking about the Perl interface to concurrency, but
you seem to contradict yourself because message passing is explicit
whereas shared memory is implicit - two different models, both of
which could be used together to implement a pretty flexible system.

It'd be a shame to not provide a way to both use threads directly or
to fallback to some implicitly concurrent constructs.

Brett

-- 
B. Estrade estr...@gmail.com


Re: threads?

2010-10-13 Thread B. Estrade
On Tue, Oct 12, 2010 at 07:22:33AM -0700, Damian Conway wrote:
 Leon Timmermans wrote:
 
  For the love of $DEITY, let's please not repeat ithreads!
 
 $AMEN!
 
 Backwards compatibility is not the major design criterion for Perl 6,
 so there's no need to recapitulate our own phylogeny here.
 
 The problem is: while most people can agree on what have proved to be
 unsatisfactory threading models, not many people can seem to agree on
 what would constititute a satisfactory threading model (or, possibly, models).
 
 What we really need is some anecdotal evidence from folks who are actually
 using threading in real-world situations (in *any* languages). What has worked
 in practice? What has worked well? What was painful? What was error-prone?
 And for which kinds of tasks?
 
 And we also need to stand back a little further and ask: is threading
 the right approach at all? Do threads work in *any* language? Are there
 better metaphors?

A more general metaphore would be asynchronous tasking, a thread being
a long running implicit task. Other issues include memory
consistency models, tasking granularity, scheduling, and flexible
synchronization options.

I am coming from the OpenMP world, so a lot of this falls on the
shoulders of the runtime - a clear strength of Perl IMHO. It may be
worth someone taking the time to read what the OpenMP spec has to say
about tasking as well as exploring tasking support on Chapel,
Fortress, X10, and Cilk. PGAS based languages may also offer some
inspirations as a potential alternative to threads or tasks. 

The only scriping language that I know that supports threading
natively is Qore. I've mentioned this before.

Perl's functional aspects also make it fairly easy to create
concurrency without the worry of side effects, but not everyone
is lucky enough to have a loosely coupled problem or not need i/o.

Now how to distill what's been learned in practice into a Perlish
approach?

 
 Perhaps we need to think more Perlishly and reframe the entire question.
 Not: What threading model do we need?, but: What kinds of non-sequential
 programming tasks do we want to make easy...and how would we like to be
 able to specify those tasks?

There are something like 12 HPC domains that have been identified,
all needing something a little different from the compiler, runtime,
and platform - these do not include things for which Perl is often
(ab)used.

 
 As someone who doesn't (need to) use threading to solve the kinds of
 problems I work on, I'm well aware that I'm not the right person to help
 in this design work. We need those poor souls who already suffer under
 threads to share their tales of constant misery (and their occasional
 moments of triumph) so we can identify successful patterns of use
 and steal^Wborg^Wborrow the very best available solutions.

Are you sure you couldn't use threading over shared memory? :)

Cheers,
Brett

 
 Damian

-- 
B. Estrade estr...@gmail.com


Re: threads?

2010-10-13 Thread B. Estrade
On Tue, Oct 12, 2010 at 02:31:26PM +0200, Carl M?sak wrote:
 Ben ():
  If perl6 can statically (at compile time) analyse subroutines and
  methods and determine if they're reentrant, then it could
  automatically use the lightest weight threads when it knows that the
  entry sub won't have side effects or alter global data.
 
 I'm often at the receiving end of this kind of reply, but...
 
 ...to a first approximation, I don't believe such analysis to be
 possible in Perl 6. Finding out whether something won't have side
 effects is tricky at best, squeezed in as we are between eval,
 exuberant dynamism, and the Halting Problem.

If one knows what variables are shared, some degree of side effect
potential can be determined. But yes, in general, a tough problem.

Brett

 
 // Carl

-- 
B. Estrade estr...@gmail.com


Re: threads? - better metaphors

2010-10-13 Thread Todd Olson

On 2010-Oct-12, at 10:22, Damian Conway wrote:

 What we really need is some anecdotal evidence from folks who are actually
 using threading in real-world situations (in *any* languages). What has worked
 in practice? What has worked well? What was painful? What was error-prone?
 And for which kinds of tasks?
 
 And we also need to stand back a little further and ask: is threading
 the right approach at all? Do threads work in *any* language? Are there
 better metaphors?


 'Channels are a good model of the external world' - Russ Cox
  Threads without Locks, slide 39

Perhaps the work on the 'channel' model done in Plan9 (and Inferno) will be 
helpful.
It has many years of experience in publicly available code, libraries, and 
discussion
archives, and verification tools.

Particularly the work of Russ Cox
   http://swtch.com/~rsc/

Particularly 
   Threads without Locks
   Bell Labs, Second International Plan 9 Workshop, December 2007
   http://swtch.com/~rsc/talks/threads07/

This talk has a nice crisp overview of the issues in different models
and mentions several real world applications

   concurrent prime sieve (by Mcllroy)
   file system indexer implementation
   publish and subscribe
   re-entrant IO multiplexing window systems
 http://swtch.com/~rsc/thread/cws.pdf   -- amazing 
stuff!
 http://video.google.com/videoplay?docid=810232012617965344
   the classic 'Squinting at Power Series' - and several others (see slide 31)
 http://swtch.com/~rsc/thread/squint.pdf
 (this could be an excellent test suite of any 'threading' implementation)

and extended in the work of PlanB  
 http://lsub.org/ls/planb.html
 http://lsub.org/index.html#demos



This model is available on many OSs in the port of Plan9 to user space
  http://swtch.com/plan9port/
and in C based libthread that builds multiple-reader, multiple-writer finite 
queues.
There is a lot to like and borrow from Plan9, including the 9P2000 protocol as 
a core organizing meme
  http://9p.cat-v.org/faq

The 'Spin' verification tool and it's history are *very* interesting also
  http://swtch.com/spin/


Note that many of the people doing 'go' were the ones that did Plan9 


Regards,
Todd Olson

PS   I'd really like to have their channel model available in Perl6
 Many things I'd like to model would work well with channels
 I have (unpublished) Perlish syntax to lay over channels

PPS  Russ has also done some nice work on regular expression engines
   http://swtch.com/~rsc/regexp/

Re: threads?

2010-10-12 Thread Leon Timmermans
On Mon, Oct 11, 2010 at 12:32 AM, Ben Goldberg ben-goldb...@hotmail.com wrote:
 If thread-unsafe subroutines are called, then something like ithreads
 might be used.

For the love of $DEITY, let's please not repeat ithreads!


Re: threads?

2010-10-12 Thread Damian Conway
Leon Timmermans wrote:

 For the love of $DEITY, let's please not repeat ithreads!

$AMEN!

Backwards compatibility is not the major design criterion for Perl 6,
so there's no need to recapitulate our own phylogeny here.

The problem is: while most people can agree on what have proved to be
unsatisfactory threading models, not many people can seem to agree on
what would constititute a satisfactory threading model (or, possibly, models).

What we really need is some anecdotal evidence from folks who are actually
using threading in real-world situations (in *any* languages). What has worked
in practice? What has worked well? What was painful? What was error-prone?
And for which kinds of tasks?

And we also need to stand back a little further and ask: is threading
the right approach at all? Do threads work in *any* language? Are there
better metaphors?

Perhaps we need to think more Perlishly and reframe the entire question.
Not: What threading model do we need?, but: What kinds of non-sequential
programming tasks do we want to make easy...and how would we like to be
able to specify those tasks?

As someone who doesn't (need to) use threading to solve the kinds of
problems I work on, I'm well aware that I'm not the right person to help
in this design work. We need those poor souls who already suffer under
threads to share their tales of constant misery (and their occasional
moments of triumph) so we can identify successful patterns of use
and steal^Wborg^Wborrow the very best available solutions.

Damian


RE: threads?

2010-10-12 Thread philippe.beauchamp
Although anecdotal, I've heard good things about Go's channel mechanism as a 
simple lightweight concurrency model and a good alternative to typical 
threading. Channels are first-class in the language and leverage simple 
goroutine semantics to invoke concurrency.


--- Phil



-Original Message-
From: thoughtstr...@gmail.com [mailto:thoughtstr...@gmail.com] On Behalf Of 
Damian Conway
Sent: October 12, 2010 10:23 AM
To: perl6-language@perl.org
Subject: Re: threads?

Leon Timmermans wrote:

 For the love of $DEITY, let's please not repeat ithreads!

$AMEN!

Backwards compatibility is not the major design criterion for Perl 6,
so there's no need to recapitulate our own phylogeny here.

The problem is: while most people can agree on what have proved to be
unsatisfactory threading models, not many people can seem to agree on
what would constititute a satisfactory threading model (or, possibly, models).

What we really need is some anecdotal evidence from folks who are actually
using threading in real-world situations (in *any* languages). What has worked
in practice? What has worked well? What was painful? What was error-prone?
And for which kinds of tasks?

And we also need to stand back a little further and ask: is threading
the right approach at all? Do threads work in *any* language? Are there
better metaphors?

Perhaps we need to think more Perlishly and reframe the entire question.
Not: What threading model do we need?, but: What kinds of non-sequential
programming tasks do we want to make easy...and how would we like to be
able to specify those tasks?

As someone who doesn't (need to) use threading to solve the kinds of
problems I work on, I'm well aware that I'm not the right person to help
in this design work. We need those poor souls who already suffer under
threads to share their tales of constant misery (and their occasional
moments of triumph) so we can identify successful patterns of use
and steal^Wborg^Wborrow the very best available solutions.

Damian


Re: threads?

2010-10-12 Thread Matthew Walton
Damian, I use threads in C++ a lot in my day to day job. We use an
in-house library which isn't much more than a thread class which you
inherit from and give a Run method to, and a load of locks of various
(sometimes ill-defined) kinds.

Let me say: it's not good. Threads with semaphores and mutexes and all
that are just horrible, horrible things. It's probably not helped at
all by how C++ itself has no awareness at all of the threading, so
there are no hints in the code that something runs in a particular
thread, you can't put lock preconditions on functions or data
structures or anything like that...

I'm not sure what a better model is, but what I'd like to see is
something which:

- can enforce that certain bits of data are only accessed if you have
certain locks, at compile time
- can enforce that certain bits of code can only be run when you have
certain locks, at compile time
- can know that you shouldn't take lock B before lock A if you want to
avoid a deadlock
- uses a completely different model that nobody's probably thought of
yet where none of this matters because all those three things are
utterly foul

I always liked Software Transactional Memory, which works very nicely
in Haskell - but not for all solutions. Whatever concurrency model
Perl 6 might support, it's probably going to need more than one of
them. Since the language is so extensible, it may be that the core
should only implement the very basic primitives, and then there are
libraries which provide the rest - some of which might ship alongside
the compiler. I don't know, but I do not want people to end up having
to count semaphores and verify locking integrity by eye because it's
really, truly horrible.

I did read a bit about Go's mechanism, and it did look interesting.
Some systems are very well-modelled as completely independent
processes (which might be threads) throwing messages at each other...

Actually something that's very nice as a mental model for server-type
systems is a core routine which responds to a trigger (say, a new
connection) by spawning a new thread to handle it, which is the only
thing which handles it, and maybe uses something like channels to
interact with any global data store that's required. For that though
you need cheap thread creation or easy thread pool stuff, and you need
to have a global data model which isn't going to completely bottleneck
your performance.

I'm totally rambling now, but I do get the distinct impression from
all my experience that safe concurrency is very difficult to do
quickly in the general case. Of course, the safest concurrency boils
down to sequencing everything and running it all on one core...

On 12 October 2010 16:25,  philippe.beauch...@bell.ca wrote:
 Although anecdotal, I've heard good things about Go's channel mechanism as 
 a simple lightweight concurrency model and a good alternative to typical 
 threading. Channels are first-class in the language and leverage simple 
 goroutine semantics to invoke concurrency.


 --- Phil



 -Original Message-
 From: thoughtstr...@gmail.com [mailto:thoughtstr...@gmail.com] On Behalf Of 
 Damian Conway
 Sent: October 12, 2010 10:23 AM
 To: perl6-language@perl.org
 Subject: Re: threads?

 Leon Timmermans wrote:

 For the love of $DEITY, let's please not repeat ithreads!

 $AMEN!

 Backwards compatibility is not the major design criterion for Perl 6,
 so there's no need to recapitulate our own phylogeny here.

 The problem is: while most people can agree on what have proved to be
 unsatisfactory threading models, not many people can seem to agree on
 what would constititute a satisfactory threading model (or, possibly, models).

 What we really need is some anecdotal evidence from folks who are actually
 using threading in real-world situations (in *any* languages). What has worked
 in practice? What has worked well? What was painful? What was error-prone?
 And for which kinds of tasks?

 And we also need to stand back a little further and ask: is threading
 the right approach at all? Do threads work in *any* language? Are there
 better metaphors?

 Perhaps we need to think more Perlishly and reframe the entire question.
 Not: What threading model do we need?, but: What kinds of non-sequential
 programming tasks do we want to make easy...and how would we like to be
 able to specify those tasks?

 As someone who doesn't (need to) use threading to solve the kinds of
 problems I work on, I'm well aware that I'm not the right person to help
 in this design work. We need those poor souls who already suffer under
 threads to share their tales of constant misery (and their occasional
 moments of triumph) so we can identify successful patterns of use
 and steal^Wborg^Wborrow the very best available solutions.

 Damian




On 12 October 2010 16:25,  philippe.beauch...@bell.ca wrote:
 Although anecdotal, I've heard good things about Go's channel mechanism as 
 a simple lightweight concurrency model and a good alternative to typical

Re: threads?

2010-10-12 Thread Jon Lang
When Larry decided that Perl 6 would incorporate concepts from
prototype-based objects, he did so at least in part because it's more
intuitive for people to work with, e.g., a cow than it is to try to
work with the concept of a cow as a thing unto itself.  In a similar
way, I think that Perl's dominant concurrency system ought to be of a
type that people who aren't computer scientists can grok, at least
well enough to do something useful without first having to delve into
the arcane depths of computing theory.

As such, I'm wondering if an Actor-based concurrency model[1] might be
a better way to go than the current threads-based mindset.  Certainly,
it's often easier to think of actors who talk to each other to get
things done than it is to think of processes (or threads) as things
unto themselves.

[1] http://en.wikipedia.org/wiki/Actor_model

-- 
Jonathan Dataweaver Lang


Re: threads?

2010-10-12 Thread Leon Timmermans
On Tue, Oct 12, 2010 at 4:22 PM, Damian Conway dam...@conway.org wrote:
 The problem is: while most people can agree on what have proved to be
 unsatisfactory threading models, not many people can seem to agree on
 what would constititute a satisfactory threading model (or, possibly, models).

 What we really need is some anecdotal evidence from folks who are actually
 using threading in real-world situations (in *any* languages). What has worked
 in practice? What has worked well? What was painful? What was error-prone?
 And for which kinds of tasks?

Most languages either implement concurrency in a way that's not very
useful (CPython, CRuby) or implement it in a way that's slightly
(Java/C/C++) to totally (perl 5) insane. Erlang is the only language
I've worked with whose threads I really like, but sadly it's rather
weak at a lot of other things.

In general, I don't feel that a shared memory model is a good fit for
a high level language. I'm very much a proponent of message passing.
Unlike shared memory, it's actually easier to do the right thing than
not. Implementing it correctly and efficiently is not easier than
doing a shared memory system though in my experience (I'm busy
implementing it on top of ithreads; yeah I'm masochist like that).

 And we also need to stand back a little further and ask: is threading
 the right approach at all? Do threads work in *any* language? Are there
 better metaphors?

 Perhaps we need to think more Perlishly and reframe the entire question.
 Not: What threading model do we need?, but: What kinds of non-sequential
 programming tasks do we want to make easy...and how would we like to be
 able to specify those tasks?

I agree. I would prefer implicit over explicit concurrency wherever possible.


Re: threads?

2010-10-12 Thread Leon Timmermans
On Tue, Oct 12, 2010 at 10:28 PM, B. Estrade estr...@gmail.com wrote:
 I agree. I would prefer implicit over explicit concurrency wherever possible.

 I know you're speaking about the Perl interface to concurrency, but
 you seem to contradict yourself because message passing is explicit
 whereas shared memory is implicit - two different models, both of
 which could be used together to implement a pretty flexible system.

With implicit I mean stuff like concurrent hyperoperators and
junctions. Shared memory systems are explicitly concurrent to me
because you have to ether explicitly lock or explicitly do a
transaction.

 It'd be a shame to not provide a way to both use threads directly or
 to fallback to some implicitly concurrent constructs.

I agree


Re: threads?

2010-10-12 Thread Dave Whipp

Damian Conway wrote:



Perhaps we need to think more Perlishly and reframe the entire question.
Not: What threading model do we need?, but: What kinds of non-sequential
programming tasks do we want to make easy...and how would we like to be
able to specify those tasks?



The mindset that I use goes something like most tasks are potentially 
concurrent: sequentialization is an optimization that most people 
perform without even thinking.


Generally, I would split concurrency into producer-consumer (i.e. 
message passing) and stream-processing (for hyper and reduction 
operators -- possibly also for feeds, with a kernel per step). When 
dealing with compute-tasks, you're basically just choosing how to map a 
dependency graph to the available compute resources. When dealing with 
external resources (e.g. sockets, GUI) then explicit parallelism (via 
message passing) becomes useful.


P6 already specifies a whole bunch of non-sequential tasks (hypers, 
reductions, feeds, background-lazy lists), so no need to reframe the 
entire question just yet. Implementing the existing concurrency will 
flush out plenty of flaws in the specs.


Re: threads?

2010-10-12 Thread Karl Brodowsky
I agree that threads are generelly a difficult issue to cope.  What is
worse, there are a lot of Java-developers who tell us, that it is not
difficult for them,
but in the end the software fails on the productive system, for example
because the load is different then on the test system, causing different
threads
to be slowed down to a different extent etc.  So people who are having
difficulties with multithreading still use them a lot and don't admit
the difficulties
and they might not even appear during testing...

Even though I did see software that heavily uses multithreading and
works well.

On the other hand I think that there are certain tasks that need to use
some kind of parallelism, either for making use of parallel CPU
infrastructure or
for implementing patterns that can more easily be expressed using
something like multithreading.

I think that the approach of running several processes instead of
several threads is something that can be considered in some cases, but I
think it does
come with a performance price tag that might not be justified in all
situations.

Maybe the actor model from Scala is worth looking at, at least the
Scala-guys claim that that solves the issue, but I don't know if that
concept can easily
be adapted for Perl 6.

Best regards,

Karl



Re: Threads and Progress Monitors

2003-05-31 Thread Dulcimer

--- Dave Whipp [EMAIL PROTECTED] wrote:
 Dulcimer wrote:
 sub slow_fn {
my $tick = Timer.new(60, { print ... });
return slow_fn_imp @_;
 }
 
 Now if I could just get the compiler to not complain about that
 unused variable...
  
  
  Maybe I'm being dense
  Why not just
   sub slow_fn {
 Timer.new(1, { print . });
 return slow_fn_imp @_;
   }

Geez. I read my response this morning, which I wrote just before going
to bed, and realized that I must've been dead on my feet.

 The problem is that I want the timer to last for the duration of the 
 slow_fn_imp. If I don't assign it to a variable, then it may be GCed
 at any time.

I was making several assumptions which don't hold, apparently, such as
that the underlying Timer would iterate until stopped. Not an ideal
default, lol I thopught the point was to have the function print
dots repeatedly, tho?

 I've just realised, however, that I'm relying on it being destroyed
 on leaving the scope. I'm not sure that the GC guarentees that.
 I might need
 
sub slow_fn {
  my $timer is last { .stop } = Timer.new(60, { print . });
  return slow_fn_imp @_;
}
 
 but that's starting to get cluttered again.

I don't really consider that clutter. It's clear and to the point,
and Does What You Want. How about 

  sub slow_fn {
my $timer is last { .stop } = 
   new Timer secs = 1, reset = 1, code = {print .};
return slow_fn_imp @_;
  }

so that the timer goes off after a second, prints a dot, and resets
itself to go off again after another second? And I still like the idea
of an expanding temporal window between dots:

  sub slow_fn {
my $pause = 1;
my $timer is last { .stop } = new Timer secs = $pause++,
   reset = {$pause++},
code = {print .};
return slow_fn_imp @_;
  }

As a sidenote, although it would actually reduce readability here, I'm
still trying to wrap my brain thoroughly around the new dynamics of $_.
Would this work correctly maybe?

  sub slow_fn {
my $timer is last { .stop } = new Timer secs = $_=1,
   reset = {$_++},
code = {print .};
return slow_fn_imp @_;
  }

Isn't that $_ proprietary to slow_fn such that it *would* work?

__
Do you Yahoo!?
Yahoo! Calendar - Free online calendar with sync to Outlook(TM).
http://calendar.yahoo.com


Re: Threads and Progress Monitors

2003-05-30 Thread Austin Hastings

--- Dave Whipp [EMAIL PROTECTED] wrote:
 OK, we've beaten the producer/consumer thread/coro model to death.
 Here's a
 different use of threads: how simple can we make this in P6:
 
   sub slow_func
   {
   my $percent_done = 0;
   my $tid = thread { slow_func_imp( \$percent_done ) };
   thread { status_monitor($percent_done) and sleep 60 until
 $tid.done };
   return wait $tid;
   }
 
 I think this would work under Austin's A17; but it feels a bit
 clunky. The
 fact that the sleep 60 isn't broken as soon as the function is done
 is
 untidy, though I wouldn't want to start killing thread.
 
 perhaps:
 
   {
   ...
   $tid = thread { slow... }
   status_monitor(\$percent_done) and wait(60 | $tid) until
 $tid.done;
   return $tid.result;
   }
 
 The thing is, that wait 60 probably can't work -- replace C60
 with
 C$period, and the semantics change. There are some obvious hacks
 that
 could work here: but is there a really nice solution. Ideally, we
 won't need
 the low level details such as C$tid

sub slow_func_imp {
  my $pct_done = 0;
  ...
  yield $pct_done++;   # Per my recent message
  ...
}

sub slow_func {
  my $tid := thread slow_func_imp;

  status_monitor($tid.resume)
while $tid.active;
}




Re: Threads and Progress Monitors

2003-05-30 Thread Michael Lazzaro
On Thursday, May 29, 2003, at 10:47 AM, Dave Whipp wrote:

OK, we've beaten the producer/consumer thread/coro model to death. 
Here's a
different use of threads: how simple can we make this in P6:
Hey, good example.  Hmm...

Well, for starters I think it wouldn't be a big deal to associate a 
progress attribute with each thread object.  It should be that 
thread's responsibility to fill it out, if it wants to -- so you 
shouldn't ever have to pass \$percent_done as an argument, it should be 
a basic attribute of every thread instance.  That might encourage 
people to add progress calculations to their threads after-the-fact, 
without changing the basic interface of what they wrote.

I'll also claim that I would still prefer the auto-parallel, 
auto-lazy-blocking behavior on the thread results we've mused about 
previously.  So coming from the semantics end, I'd love to see it 
written like this:

   # Declaring a threaded calculation

   sub slow_func_impl is threaded {
   while (...stuff...) {
   ... do stuff ...
   _.thread.progress += 10.0;   # or however you want to 
guesstimate[*] this
   }
   return $result;
   }

   # If you don't care about getting the actual thread object, just the 
result,
   # call it this way:

   {
   ...
   my $result = slow_func_impl(...);
   ...
   return $result;
   }
   # But if you want to get the thread object, so you can monitor it's 
progress,
   # call it this way:

   {
   ...
   my $tid = thread slow_func_impl(...);
   while $tid.active {
   status_monitor($tid.progress);
   sleep 60;
   }
   return $tid.result;
   }
To my eye, that looks pretty darn slick.

MikeL

[*] Huh.  Imagine my surprise to find out that my spellcheck considers 
guesstimate to be a real word.  And I always thought that was just a 
spasmostical pseudolexomangloid.



Re: Threads and Progress Monitors

2003-05-30 Thread Dave Whipp
Michael Lazzaro [EMAIL PROTECTED] wrote in # But if you want
to get the thread object, so you can monitor it's

 {
 ...
 my $tid = thread slow_func_impl(...);
 while $tid.active {
 status_monitor($tid.progress);
 sleep 60;
 }
 return $tid.result;
 }

 To my eye, that looks pretty darn slick.

You might be a bit frustrated if the slow_func_impl took 61 seconds :-(.
How do we interrupt the Csleep? Possibly in the same way as we'd timeout a
blocking IO operations. But I wonder if this could work:

  my $tid = thread slow_func_impl(...);
  until wait $tid, timeout=60
  {
  status_monitor($tid.progress);
  }
  return $tid.result;

Here I assume that Cwait returns a true value if its waited condition
occurs, but false if it times out.

Hmm, A few days ago I tried indroducing a syntax for thread with a
sensitivity list in place of an explict loop-forever thread. Perhaps I can
reuse that syntax:

  my $tid = thread slow_func_impl(...);
  thread $tid | timeout(60)
  {
  when $tid = { return $tid.result }
  default = { status_monitor $tid.progress }
  }

Perhaps a different keyword would be better: Calways as the looping
counterpart to Cwait -- then extend Cwait to accept a code block.

Dave.




Re: Threads and Progress Monitors

2003-05-30 Thread John Macdonald
On Thu, May 29, 2003 at 10:47:35AM -0700, Dave Whipp wrote:
 OK, we've beaten the producer/consumer thread/coro model to death. Here's a
 different use of threads: how simple can we make this in P6:
 
   sub slow_func
   {
   my $percent_done = 0;
   my $tid = thread { slow_func_imp( \$percent_done ) };
   thread { status_monitor($percent_done) and sleep 60 until
 $tid.done };
   return wait $tid;
   }

At first glance, this doesn't need a thread - a
coroutine is sufficient.  Resume the status update
coroutine whenever there has been some progress.
It doesn't wait and poll a status variable, it just
let the slow function work at its own speed without
interruption until there is a reason to change the
display.

In fact, it probably doesn't need to be a coroutine
either.  A subroutine - display_status( $percent ) -
should't require any code state to maintain, just a
bit if data so all it needs is a closure or an object.

At second glance, there is a reason for a higher
powered solution.  If updating the display to a new
status takes a significant amount of time, especially
I/O time, it would both block the slow function
unnecessarily and would update for every percent
point change.  Using a separate process or thread
allows the function to proceed without blocking, and
allows the next update to jmp ahead to the current
actual level, skipping all of the levels that occurred
while the previous display was happening.  Instead of
sleep, though, I'd use a pipeline and read it with
a non-blocking read until there is no data.  Then,
if the status has changed since the last update, do
a display update and repeat the non-blocking read.
If the status has not changed, do a blocking read to
wait for the next status change.


Re: Threads and Progress Monitors

2003-05-30 Thread Dave Whipp
John Macdonald [EMAIL PROTECTED] wrote  At first glance, this
doesn't need a thread - a
  Instead of
 sleep, though, I'd use a pipeline and read it with
 a non-blocking read until there is no data.  ...

++ For the lateral thinking. Definitely a valid solution to the problem, as
given. So I'll change the problem prevent it: the slow fn is a 3rd-party
blob with no access to source code and no progress indication.

sub slow_fn {
   print starting slow operation: this sometimes takes half an hour!\n;
   my $tid = thread { slow_fn_imp @_ };
   $start = time;
   loop {
   wait $tid | timeout(60);
   return $tid.result if $tid.done;
   print ... $(time-$start) seconds\n;
   }
}

Still a bit too complex for my taste: perhaps we can use Ctimeout to
generate exceptions:

  my lazy::threaded $result := { slow_fn_imp @_ };
  loop {
timeout(60);
return $result;
CATCH Timeout { print ...$(time)\n }
 }

At last, no Ctid! (Reminder: the suggested semantics of the threaded
variable were that a FETCH to it blocks until the result of the thread is
available).


Dave.




Re: Threads and Progress Monitors

2003-05-30 Thread Luke Palmer
Dave wrote:
 Still a bit too complex for my taste: perhaps we can use Ctimeout to
 generate exceptions:
 
   my lazy::threaded $result := { slow_fn_imp @_ };
   loop {
 timeout(60);
 return $result;
 CATCH Timeout { print ...$(time)\n }
  }
 
 At last, no Ctid! (Reminder: the suggested semantics of the threaded
 variable were that a FETCH to it blocks until the result of the thread is
 available).

To nitpick:

my $result is lazy::threaded := { slow_fn_imp @_ };

Because lazy::threaded isn't the Ireturn type, it's the Ivariable
type.

loop {
timeout(60);
return $result;
CATCH {
when Timeout { print ...$(time)\n
}
}

Because CCATCH is like Cgiven $!.

I like that elegant use of threaded variables, by the way.

Now write the Ctimeout function :-P.

Luke


Re: Threads and Progress Monitors

2003-05-30 Thread Michael Lazzaro
On Thursday, May 29, 2003, at 12:45 PM, Dave Whipp wrote:
Michael Lazzaro [EMAIL PROTECTED] wrote in # But if 
you want
to get the thread object, so you can monitor it's
{
...
my $tid = thread slow_func_impl(...);
while $tid.active {
status_monitor($tid.progress);
sleep 60;
}
return $tid.result;
}
To my eye, that looks pretty darn slick.
You might be a bit frustrated if the slow_func_impl took 61 seconds 
:-(.
How do we interrupt the Csleep? Possibly in the same way as we'd 
timeout a
blocking IO operations.
Personally, I'd be happy with just making the Csleep a smaller 
number, like one second, or a fifth of a second, or whatever.  You want 
the status_monitor to be updated no more often than it needs to be, but 
often enough that it's not lagging.

But if you really wanted wake-immediately-upon-end, I'd add that as a 
variant of Csleep.  For example, you might want a variant that 
blocked until a given variable changed, just like in debuggers; that 
would allow:

{
my $tid = thread slow_func_impl(...);
while $tid.active {
status_monitor($tid.progress);
sleep( 60, watch = \($tid.progress) ); # do you even 
need the '\'?
}
return $tid.result;
}

... which would sleep 60 seconds, or until the .progress attribute 
changed, whichever came first.

You could make more builtins for that, but I think I'd like them to 
just be Csleep or Cwait variants.  Obvious possibilities:

sleep 60; # sleep 60 seconds
sleep( block = $tid );   # sleep until given thread is complete
sleep( watch = \$var );  # sleep until given var changes value
sleep( 60, block = $tid, watch = [\$var1, \$var2, \$var3] );  
five tests

$tid.sleep(...);# sleep the given thread, instead of this one

MikeL



Re: Threads and Progress Monitors

2003-05-30 Thread Michael Lazzaro
On Thursday, May 29, 2003, at 04:48 PM, Luke Palmer wrote:
To nitpick:

my $result is lazy::threaded := { slow_fn_imp @_ };
Pursuing this lazy-threaded variables notion, a question.  Given:

 sub slow_func is threaded {# me likey this 
auto-parallelizing syntax!
 ...
 }

Would we want to say that _both_ of these have the lazy-blocking 
behavior?

 my $result := slow_func();
 print $result;
 my $result  = slow_func();
 print $result;
Or would the first one block at Cprint, but the second block 
immediately at the C=?

The obvious answer is that the := binding passes through the 
lazyness, but the = assignment doesn't.  But I wonder if that isn't a 
bit too obscure, to put it mildly.

MikeL



Re: Threads and Progress Monitors

2003-05-30 Thread Dulcimer

 sub slow_fn {
my $tick = Timer.new(60, { print ... });
return slow_fn_imp @_;
 }
 
 Now if I could just get the compiler to not complain about that
 unused variable...

Maybe I'm being dense
Why not just
 sub slow_fn {
   Timer.new(1, { print . });
   return slow_fn_imp @_;
 }

or maybe even

 sub slow_fn {
   my $tick = 1;
   Timer.new({$tick++}, { print . });
   return slow_fn_imp @_;
 }
For a slowly slowing timer
?

Or to my taste,
 sub slow_fn {
   Timer.new(60, { print ... });
   return slow_fn_imp @_;
 }

__
Do you Yahoo!?
Yahoo! Calendar - Free online calendar with sync to Outlook(TM).
http://calendar.yahoo.com


Re: Threads and Progress Monitors

2003-05-30 Thread Dave Whipp
Dulcimer wrote:
sub slow_fn {
  my $tick = Timer.new(60, { print ... });
  return slow_fn_imp @_;
}
Now if I could just get the compiler to not complain about that
unused variable...


Maybe I'm being dense
Why not just
 sub slow_fn {
   Timer.new(1, { print . });
   return slow_fn_imp @_;
 }
The problem is that I want the timer to last for the duration of the 
slow_fn_imp. If I don't assign it to a variable, then it may be GCed at 
any time.

I've just realised, however, that I'm relying on it being destroyed on 
leaving the scope. I'm not sure that the GC guarentees that. I might need

  sub slow_fn {
my $timer is last { .stop } = Timer.new(60, { print . });
return slow_fn_imp @_;
  }
but that's starting to get cluttered again.

Dave.



Re: Threads and Progress Monitors

2003-05-30 Thread Paul Johnson

Dave Whipp said:

 I've just realised, however, that I'm relying on it being destroyed on
 leaving the scope. I'm not sure that the GC guarentees that.

GC doesn't, but I would be surprised if Perl 6 doesn't and in that case
Parrot will be accommodating.

Take a look at the recent p6i archives for the gory details.

-- 
Paul Johnson - [EMAIL PROTECTED]
http://www.pjcj.net



Re: Threads and run time/compile time

2000-08-27 Thread Chaim Frenkel

I wish I knew why you are discussing in -internals issue on this list.
You should be specifying behaviour not how it is implemented. A mention
of implementation is reasonable but _don't_ spend too much time. If Larry
wants it. -internals will give it to him.

Anyway, please recall that because of threading concerns, the final
internal form of any compiled piece of code will be as immutable as
possible. So that if another thread needs to reslurp a module, the
compiled form will be available.

Of course, some initializations would have to be rerun, but that is
minor compared to the other costs.

Remember specify _as if_ it would do X. -internals will make it so.
As fast as possible. 

chaim
(Of course some requests will not be doable and some revisitin will
have to be performed but the first cut should not be too concerned.)
c

 "SWM" == Steven W McDougall [EMAIL PROTECTED] writes:

SWM Based on your examples, I have to assume that you are serious about
SWM RFC1v3 item 6:

SWM 6. Modules should be loaded into the thread-global space when used
SWM[...]
SWMSubsequent threads should then reslurp these modules back in on 
SWMtheir start up.
SWM[...]
SWMeach thread needs to reuse the original modules upon creation.
SWM[...]
SWMThis, of course, could lead to massive program bloat


SWM This is a non-starter for me. Right now, I am working on apps that may
SWM create 10 threads per *second*. I cannot possibly get the performance
SWM I need if every thread has to recompile all its own modules.

SWM We could either discuss alternate approaches for RFC1, or I could
SWM submit a new RFC for a thread architecture that gives me the
SWM performance I want.
-- 
Chaim FrenkelNonlinear Knowledge, Inc.
[EMAIL PROTECTED]   +1-718-236-0183