RSS 2.0

Personal Info:

Joe Send mail to the author(s) leads the architecture of an experimental OS's developer platform, where he is also chief architect of its programming language. His current mission is to enable writing large-scale software that is reliable, secure, and scalable by-construction. Before this, Joe founded the Parallel Extensions to .NET project. He has been granted 19 patents, with 49 pending. When not working, Joe enjoys travelling with his wife, writing books, writing music, studying music theory & mathematics, and doing anything involving food & wine.

My books

My music

Disclaimer:
The content of this site are my own personal opinions and do not represent my employer's view in anyway.

© 2012, Joe Duffy

 
 Saturday, June 12, 2004

As I mentioned earlier, we will be relocating from Massachusetts to Washington state very shortly.

And as the plans start to materialize, I have a growing concern over our wine collection. Truthfully, the collection is not that large (on the order of 100 bottles), but the average bottle cost is moderate (probably about $60)... That's about $6k in wine - a product that is very easy to destroy with improper shipping and handling. Especially if Mother Nature decides to conjur up any extreme weather during the move.

It's not just the cost of replacement that I'm worried about, but rather a combination of other factors too

  • Some collector's vintages, such as 1999 Chateau Mouton Rothschild and Almaviva, 1999 Castello Banfi Excelsus and Summus, and a vast array of 1997 and 1999 Brunello di Montalcinos;
  • Major sentimental value;
  • Most likely, it'd be a “wait and see” game to find out which - if any - were ruined in the move... imagine the disappointment of uncorking a $300 bottle of wine only to find out that it's ruined;
  • It's taken a lot of time and careful picking to build up what we have, with an eye for vintages that age well.

So, all of these factors together are making me consider specialty shipping. But, it's expensive.

Of course we could just drink them all before we move. :)

6/12/2004 7:39:12 AM (Pacific Daylight Time, UTC-07:00)  #   

I'm currently enjoying a perfectly steeped China green tea, in particular an organic Chun Mee Dao Ming.

The dry leaf appears and has an aroma that indicates a smokiness, but this quality doesn't transfer very directly to the cup. In fact, the liquor is very smooth and wonderfully flavorful with a great full mouth feel. It has a slightly tangy flavor in there towards the finish, almost peachy but not quite fully developed. If this fruitiness had asserted itself a little bit more, I'd have fallen in love.

Still a keeper in my book.

6/12/2004 7:20:31 AM (Pacific Daylight Time, UTC-07:00)  #   

Am I on crack, or was a new drop of Visual Studio 2005 released at TechEd and immediately put up on MSDN?

The reason I wonder if I'm suffering from some sort of drug-induced hallucination is that I've seen absolutely no chatter at all coming from the blogs to which I subscribe. Very unlike the other drops. Perhaps I am tuning such discussions out subconsciously, but I don't think so.

Anyhow, I just finished the 2.5GB download... time to increase the number of Visual Studio installations on my machine to 10. :P

6/12/2004 5:39:24 AM (Pacific Daylight Time, UTC-07:00)  #   

 Wednesday, June 09, 2004

I've been toying around with C# iterators a bit more lately, particularly regarding non-mainstream applications. I discussed partial algorithm computation during a couple earlier posts (here and here), but now wish to turn to producer/consumer models. A producer/consumer model is one in which a single producer is responsible for generating items of interest, which are later processed by one or more consumers.

I really should do a bit more explanation, but for now I'll simply present some code examples with brief comments.

To wire up threaded producers and consumers, quite a bit of plumbing is required; thus, I have encapsulated it all into a couple common abstract classes:

public abstract class Producer<T>

{

 

      public Producer()

      {

            worker = new Thread(new ThreadStart(this.ProductionCycle));

      }

 

      private Queue<T> buffer = new Queue<T>();

 

      public Thread worker;

 

      private bool done;

 

      public bool Done

      {

            get

            {

                  return done;

            }

      }

 

      public IEnumerable<T> ConsumerChannel

      {

            get

            {

                  if (done)

                        throw new InvalidOperationException("Production is not currently active");

 

                  while (!done)

                  {

                        Nullable<T> consumed = new Nullable<T>();

 

                        //BUG: compiler crashes when using lock(...) construct within iterator

                        Monitor.Enter(buffer);

                        if (buffer.Count == 0)

                              Monitor.Wait(buffer);

                        if (buffer.Count > 0)

                              consumed = new Nullable<T>(buffer.Dequeue());

                        Monitor.Exit(buffer);

 

                        if (consumed.HasValue)

                              yield return consumed.Value;

                  }

 

                  yield break;

            }

      }

 

      public void BeginProduction()

      {

            done = false;

            worker.Start();

      }

 

      public void EndProduction()

      {

            done = true;

            lock (buffer)

            {

                  Monitor.PulseAll(buffer);

            }

      }

 

      private void ProductionCycle()

      {

            while (!done)

            {

                  T t = ProduceNext();

                  lock (buffer)

                  {

                        buffer.Enqueue(t);

                        Monitor.Pulse(buffer);

                  }

            }

      }

 

      protected abstract T ProduceNext();

 

}

 

public abstract class Consumer<T>

{

 

      public Consumer(Producer<T> producer)

      {

            this.producer = producer;

            worker = new Thread(new ThreadStart(this.ConsumerCycle));

      }

 

      private Producer<T> producer;

 

      public Thread worker;

 

      private bool done = false;

 

      public bool Done

      {

            get

            {

                  return done;

            }

      }

 

      public void BeginConsumption()

      {

            done = false;

            worker.Start();

      }

 

      public void EndConsumption()

      {

            done = true;

      }

 

      private void ConsumerCycle()

      {

            foreach (T t in producer.ConsumerChannel)

            {

                  Consume(t);

                  if (done)

                        break;

            }

      }

 

      protected abstract void Consume(T t);

 

}

 

(Note: I haven't spent enough time on the threading issues, and as such may have overlooked a thing or two. It's pretty messy as it stands, but it'll do for now...)

To create specific concrete classes from these, it's a matter of simply overriding a couple methods. For instance, the following producer generates a never-ending sequence of random numbers, while the consumer simply prints them out:

class RandomNumberProducer : Producer<int>

{

 

      public RandomNumberProducer() : base()

      {

            rand = new Random();

      }

 

      private Random rand;

 

      protected override int ProduceNext()

      {

            return rand.Next();

      }

 

}

 

class RandomNumberConsumer : Consumer<int>

{

 

      public RandomNumberConsumer(RandomNumberProducer p) : base(p)

      {

      }

 

      private static int counter = 0;

 

      private int id = ++counter;

 

      protected override void Consume(int t)

      {

            Console.Out.WriteLine("#{0}: consumed {1}", id, t);

      }

 

}

 

To wire them up, and kick off the cycles, the following test code does the trick:

 

RandomNumberProducer p = new RandomNumberProducer();

 

RandomNumberConsumer c1 = new RandomNumberConsumer(p);

RandomNumberConsumer c2 = new RandomNumberConsumer(p);

RandomNumberConsumer c3 = new RandomNumberConsumer(p);

 

p.BeginProduction();

 

c1.BeginConsumption();

c2.BeginConsumption();

c3.BeginConsumption();

 

Thread.Sleep(2500);

 

c3.EndConsumption();

c2.EndConsumption();

c1.EndConsumption();

 

p.EndProduction();

 

These examples probably don't quite illustrate the advantages of this approach very well. Obviously, using well factored base classes provides a lot of benefit, namely that they encapsulate and implement the threading and synchronization boilerplate. Interestingly, the iterators remove the need for the consumer to worry about any synchronization.

This means that the following simple consumer code is actually thread safe - even if there are other consumers wired up to the producer:

foreach (int i in p.ConsumerChannel)

{

      Console.Out.WriteLine("consumed: {0}", i);

}

In theory, the threading and blocking is all handled by the producer's iterator (although I question if my implementation is entirely correct).

Pretty nifty, if you ask me...

[I apologize for the hideous HTML for the code samples - I really wanted to retain the Visual Studio color scheme, and the only easy way I could find to accomplish this was to cut and paste into Word. Probably not an issue on most browsers, but just in case...]

6/9/2004 6:05:53 PM (Pacific Daylight Time, UTC-07:00)  #   

 Tuesday, June 08, 2004

Two great books are at the top of my reading stack at the moment,

Distributed Systems: Principles and Paradigms
by Andrew S. Tanenbaum, Maarten van Steen

Decent book thus far (I'm only a couple chapters in), although it feels dated. If I make it through, I'll post a detailed review about it.

and

ANSI Common Lisp
by Paul Graham

This is a re-read. Unfortunately I'm not able to work with Lisp as often as I'd like, and thus every once in a while I dust off the cobwebs. Each time I go back, I learn something new and am treated to a new perspective on everyday challenges. I want to get ahold and paw through a copy of Guy Steele's Common LISP: The Language, but as of yet have not had a chance.

6/8/2004 6:44:59 PM (Pacific Daylight Time, UTC-07:00)  #   

Upgraded to dasBlog 1.6... reworked the layout and color scheme of the site...

Just making sure it functions properly!

6/8/2004 6:20:43 PM (Pacific Daylight Time, UTC-07:00)  #   

 Friday, June 04, 2004

...comes in many forms.

(defun fib (n)
  (if (< n 2)
    1
    (+ (fib (- n 1)) (fib (- n 2)))))
   

6/4/2004 6:20:34 PM (Pacific Daylight Time, UTC-07:00)  #   

Doug Purdy posted an amusing response (and here) to the whole "DataSets are evil" argument.

To be clear, my aversion to DataSets has nothing to do with their use in web services, but rather as an overall architectural principle. As he points out (and Dare reiterates), once it escapes your application we're simply talking about schema and XML data. (Note: it's interesting to question what "it" represents in the previous sentence; it sure as hell isn't an instance of a DataSet once it reaches the wire!) The programming model is an implementation detail, and is certainly hidden behind an interface.

So if application edges are rigid and abstracted by an interface which represents data as XML, who cares in what fashion such XML is constructed? Once could - if so inclined - represent objects internally in a picture perfect domain model, yet serialize them over the wire in a horrid alphabet soup of nonsensical tags; and, conversely a DataSet could manifest on the wire as a beautiful schema-driven thing of wonder.

So, again... who really cares?

Well, I do. My comments were made focused on proper separation of concerns within application boundaries (e.g. between tiers) and through the prism of proper domain modeling. So while advertising this as a web services-specific problem is a miscategorization, I still firmly believe it's a problem.

But then again, it's all about value delivered to the end consumer. My beliefs and experience are simply that careful domain modeling more often than not results in better value and agility in the end product. And thus, I stick to my story.

6/4/2004 2:30:48 PM (Pacific Daylight Time, UTC-07:00)  #   

 Thursday, June 03, 2004

"Human beings have been reduced to consumers."

"Americans are just now waking up to the real world [of Globalization]."

"Globalization has to be a two way traffic."

The Discovery channel is currently airing a special entitled "Thomas L. Fieldman Reporting: The Other Side of Outsourcing." Its content is mainly concerned with the impacts of outsourcing on India's traditionally family- and ritual-centric culture. I still need to digest some of the information, but it's definitely an eye-opening viewpoint.

6/3/2004 7:45:03 PM (Pacific Daylight Time, UTC-07:00)  #   

I usually don't post simply for “Mindless Link Propagation” - as Dare calls it - but this post is of particular importance.

Josh Ledgard, Chief Community Evangelist at Microsoft, talks about the legal implications and challenges (via Scoble) that arise when early community involvement is solicited in the product lifecycle. It sucks big time when such legal barriers have the potential to force one to sidestep in the wrong direction... but consider the consequences. Yikes.

(BTW, I find Scoble's response pretty ignorant and childish, and akin to a teenage fit of rebellion. Dude, there's a reason legal departments restrict certain things... because there are implications should these safeguards not be put into place. Microsoft owns its IP, and as such can tell anybody - yes, even Scoble - what they are or are not able to do with it. Regardless of on whose time it occurs.)

6/3/2004 4:06:39 PM (Pacific Daylight Time, UTC-07:00)  #   

 

Recent Entries:

Search:

Browse by Date:
<June 2004>
SunMonTueWedThuFriSat
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

Browse by Category:

Notables: